1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "base64.h" 18 19 #include "ABuffer.h" 20 #include "ADebug.h" 21 22 namespace android { 23 24 sp<ABuffer> decodeBase64(const AString &s) { 25 size_t n = s.size(); 26 27 if ((n % 4) != 0) { 28 return NULL; 29 } 30 31 size_t padding = 0; 32 if (n >= 1 && s.c_str()[n - 1] == '=') { 33 padding = 1; 34 35 if (n >= 2 && s.c_str()[n - 2] == '=') { 36 padding = 2; 37 38 if (n >= 3 && s.c_str()[n - 3] == '=') { 39 padding = 3; 40 } 41 } 42 } 43 44 // We divide first to avoid overflow. It's OK to do this because we 45 // already made sure that n % 4 == 0. 46 size_t outLen = (n / 4) * 3 - padding; 47 48 sp<ABuffer> buffer = new ABuffer(outLen); 49 uint8_t *out = buffer->data(); 50 if (out == NULL || buffer->size() < outLen) { 51 return NULL; 52 } 53 size_t j = 0; 54 uint32_t accum = 0; 55 for (size_t i = 0; i < n; ++i) { 56 char c = s.c_str()[i]; 57 unsigned value; 58 if (c >= 'A' && c <= 'Z') { 59 value = c - 'A'; 60 } else if (c >= 'a' && c <= 'z') { 61 value = 26 + c - 'a'; 62 } else if (c >= '0' && c <= '9') { 63 value = 52 + c - '0'; 64 } else if (c == '+' || c == '-') { 65 value = 62; 66 } else if (c == '/' || c == '_') { 67 value = 63; 68 } else if (c != '=') { 69 return NULL; 70 } else { 71 if (i < n - padding) { 72 return NULL; 73 } 74 75 value = 0; 76 } 77 78 accum = (accum << 6) | value; 79 80 if (((i + 1) % 4) == 0) { 81 if (j < outLen) { out[j++] = (accum >> 16); } 82 if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } 83 if (j < outLen) { out[j++] = accum & 0xff; } 84 85 accum = 0; 86 } 87 } 88 89 return buffer; 90 } 91 92 static char encode6Bit(unsigned x) { 93 if (x <= 25) { 94 return 'A' + x; 95 } else if (x <= 51) { 96 return 'a' + x - 26; 97 } else if (x <= 61) { 98 return '0' + x - 52; 99 } else if (x == 62) { 100 return '+'; 101 } else { 102 return '/'; 103 } 104 } 105 106 void encodeBase64( 107 const void *_data, size_t size, AString *out) { 108 out->clear(); 109 110 const uint8_t *data = (const uint8_t *)_data; 111 112 size_t i; 113 for (i = 0; i < (size / 3) * 3; i += 3) { 114 uint8_t x1 = data[i]; 115 uint8_t x2 = data[i + 1]; 116 uint8_t x3 = data[i + 2]; 117 118 out->append(encode6Bit(x1 >> 2)); 119 out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f)); 120 out->append(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f)); 121 out->append(encode6Bit(x3 & 0x3f)); 122 } 123 switch (size % 3) { 124 case 0: 125 break; 126 case 2: 127 { 128 uint8_t x1 = data[i]; 129 uint8_t x2 = data[i + 1]; 130 out->append(encode6Bit(x1 >> 2)); 131 out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f)); 132 out->append(encode6Bit((x2 << 2) & 0x3f)); 133 out->append('='); 134 break; 135 } 136 default: 137 { 138 uint8_t x1 = data[i]; 139 out->append(encode6Bit(x1 >> 2)); 140 out->append(encode6Bit((x1 << 4) & 0x3f)); 141 out->append("=="); 142 break; 143 } 144 } 145 } 146 147 void encodeBase64Url( 148 const void *_data, size_t size, AString *out) { 149 encodeBase64(_data, size, out); 150 151 if ((-1 != out->find("+")) || (-1 != out->find("/"))) { 152 size_t outLen = out->size(); 153 char *base64url = new char[outLen]; 154 for (size_t i = 0; i < outLen; ++i) { 155 if (out->c_str()[i] == '+') 156 base64url[i] = '-'; 157 else if (out->c_str()[i] == '/') 158 base64url[i] = '_'; 159 else 160 base64url[i] = out->c_str()[i]; 161 } 162 163 out->setTo(base64url, outLen); 164 delete[] base64url; 165 } 166 } 167 168 169 } // namespace android 170