1a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor/* 2a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * Copyright (C) 2007 Esmertec AG. 3a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * Copyright (C) 2007 The Android Open Source Project 4a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * 5a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * Licensed under the Apache License, Version 2.0 (the "License"); 6a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * you may not use this file except in compliance with the License. 7a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * You may obtain a copy of the License at 8a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * 9a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * http://www.apache.org/licenses/LICENSE-2.0 10a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * 11a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * Unless required by applicable law or agreed to in writing, software 12a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * distributed under the License is distributed on an "AS IS" BASIS, 13a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * See the License for the specific language governing permissions and 15a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * limitations under the License. 16a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor */ 17a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 18a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylorpackage com.google.android.mms.pdu; 19a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 20a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylorpublic class Base64 { 21a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor /** 22a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * Used to get the number of Quadruples. 23a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor */ 24a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor static final int FOURBYTE = 4; 25a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 26a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor /** 27a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * Byte used to pad output. 28a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor */ 29a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor static final byte PAD = (byte) '='; 30a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 31a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor /** 32a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * The base length. 33a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor */ 34a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor static final int BASELENGTH = 255; 35a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 36a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor // Create arrays to hold the base64 characters 37a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor private static byte[] base64Alphabet = new byte[BASELENGTH]; 38a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 39a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor // Populating the character arrays 40a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor static { 41a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor for (int i = 0; i < BASELENGTH; i++) { 42a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor base64Alphabet[i] = (byte) -1; 43a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 44a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor for (int i = 'Z'; i >= 'A'; i--) { 45a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor base64Alphabet[i] = (byte) (i - 'A'); 46a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 47a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor for (int i = 'z'; i >= 'a'; i--) { 48a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor base64Alphabet[i] = (byte) (i - 'a' + 26); 49a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 50a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor for (int i = '9'; i >= '0'; i--) { 51a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor base64Alphabet[i] = (byte) (i - '0' + 52); 52a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 53a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 54a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor base64Alphabet['+'] = 62; 55a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor base64Alphabet['/'] = 63; 56a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 57a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 58a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor /** 59a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * Decodes Base64 data into octects 60a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * 61a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * @param base64Data Byte array containing Base64 data 62a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * @return Array containing decoded data. 63a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor */ 64a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor public static byte[] decodeBase64(byte[] base64Data) { 65a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor // RFC 2045 requires that we discard ALL non-Base64 characters 66a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor base64Data = discardNonBase64(base64Data); 67a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 68a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor // handle the edge case, so we don't have to worry about it later 69a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor if (base64Data.length == 0) { 70a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor return new byte[0]; 71a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 72a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 73a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor int numberQuadruple = base64Data.length / FOURBYTE; 74a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor byte decodedData[] = null; 75a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; 76a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 77a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor // Throw away anything not in base64Data 78a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 79a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor int encodedIndex = 0; 80a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor int dataIndex = 0; 81a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor { 82a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor // this sizes the output array properly - rlw 83a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor int lastData = base64Data.length; 84a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor // ignore the '=' padding 85a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor while (base64Data[lastData - 1] == PAD) { 86a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor if (--lastData == 0) { 87a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor return new byte[0]; 88a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 89a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 90a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor decodedData = new byte[lastData - numberQuadruple]; 91a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 92a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 93a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor for (int i = 0; i < numberQuadruple; i++) { 94a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor dataIndex = i * 4; 95a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor marker0 = base64Data[dataIndex + 2]; 96a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor marker1 = base64Data[dataIndex + 3]; 97a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 98a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor b1 = base64Alphabet[base64Data[dataIndex]]; 99a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor b2 = base64Alphabet[base64Data[dataIndex + 1]]; 100a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 101a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor if (marker0 != PAD && marker1 != PAD) { 102a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor //No PAD e.g 3cQl 103a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor b3 = base64Alphabet[marker0]; 104a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor b4 = base64Alphabet[marker1]; 105a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 106a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 107a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor decodedData[encodedIndex + 1] = 108a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 109a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4); 110a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } else if (marker0 == PAD) { 111a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor //Two PAD e.g. 3c[Pad][Pad] 112a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 113a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } else if (marker1 == PAD) { 114a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor //One PAD e.g. 3cQ[Pad] 115a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor b3 = base64Alphabet[marker0]; 116a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 117a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 118a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor decodedData[encodedIndex + 1] = 119a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 120a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 121a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor encodedIndex += 3; 122a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 123a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor return decodedData; 124a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 125a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 126a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor /** 127a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * Check octect wheter it is a base64 encoding. 128a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * 129a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * @param octect to be checked byte 130a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * @return ture if it is base64 encoding, false otherwise. 131a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor */ 132a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor private static boolean isBase64(byte octect) { 133a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor if (octect == PAD) { 134a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor return true; 135a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } else if (base64Alphabet[octect] == -1) { 136a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor return false; 137a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } else { 138a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor return true; 139a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 140a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 141a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 142a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor /** 143a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * Discards any characters outside of the base64 alphabet, per 144a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * the requirements on page 25 of RFC 2045 - "Any characters 145a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * outside of the base64 alphabet are to be ignored in base64 146a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * encoded data." 147a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * 148a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * @param data The base-64 encoded data to groom 149a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor * @return The data, less non-base64 characters (see RFC 2045). 150a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor */ 151a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor static byte[] discardNonBase64(byte[] data) { 152a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor byte groomedData[] = new byte[data.length]; 153a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor int bytesCopied = 0; 154a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 155a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor for (int i = 0; i < data.length; i++) { 156a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor if (isBase64(data[i])) { 157a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor groomedData[bytesCopied++] = data[i]; 158a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 159a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 160a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 161a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor byte packedData[] = new byte[bytesCopied]; 162a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 163a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); 164a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor 165a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor return packedData; 166a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor } 167a87afd07c0093cab638e9ef9bc2c53c8200ca711Tom Taylor} 168