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 bufSize = n / 4 * 3; 32 sp<ABuffer> buf = new ABuffer(bufSize); 33 34 if (decodeBase64(buf->data(), &bufSize, s.c_str())) { 35 buf->setRange(0, bufSize); 36 return buf; 37 } 38 return NULL; 39 } 40 41 bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s) { 42 size_t n = strlen(s); 43 44 if ((n % 4) != 0) { 45 return false; 46 } 47 48 size_t padding = 0; 49 if (n >= 1 && s[n - 1] == '=') { 50 padding = 1; 51 52 if (n >= 2 && s[n - 2] == '=') { 53 padding = 2; 54 55 if (n >= 3 && s[n - 3] == '=') { 56 padding = 3; 57 } 58 } 59 } 60 61 // We divide first to avoid overflow. It's OK to do this because we 62 // already made sure that n % 4 == 0. 63 size_t outLen = (n / 4) * 3 - padding; 64 65 if (out == NULL || *inOutBufSize < outLen) { 66 return false; 67 } 68 size_t j = 0; 69 uint32_t accum = 0; 70 for (size_t i = 0; i < n; ++i) { 71 char c = s[i]; 72 unsigned value; 73 if (c >= 'A' && c <= 'Z') { 74 value = c - 'A'; 75 } else if (c >= 'a' && c <= 'z') { 76 value = 26 + c - 'a'; 77 } else if (c >= '0' && c <= '9') { 78 value = 52 + c - '0'; 79 } else if (c == '+' || c == '-') { 80 value = 62; 81 } else if (c == '/' || c == '_') { 82 value = 63; 83 } else if (c != '=') { 84 return false; 85 } else { 86 if (i < n - padding) { 87 return false; 88 } 89 90 value = 0; 91 } 92 93 accum = (accum << 6) | value; 94 95 if (((i + 1) % 4) == 0) { 96 if (j < outLen) { out[j++] = (accum >> 16); } 97 if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } 98 if (j < outLen) { out[j++] = accum & 0xff; } 99 100 accum = 0; 101 } 102 } 103 104 *inOutBufSize = j; 105 return true; 106 } 107 108 static char encode6Bit(unsigned x) { 109 if (x <= 25) { 110 return 'A' + x; 111 } else if (x <= 51) { 112 return 'a' + x - 26; 113 } else if (x <= 61) { 114 return '0' + x - 52; 115 } else if (x == 62) { 116 return '+'; 117 } else { 118 return '/'; 119 } 120 } 121 122 void encodeBase64( 123 const void *_data, size_t size, AString *out) { 124 out->clear(); 125 126 const uint8_t *data = (const uint8_t *)_data; 127 128 size_t i; 129 for (i = 0; i < (size / 3) * 3; i += 3) { 130 uint8_t x1 = data[i]; 131 uint8_t x2 = data[i + 1]; 132 uint8_t x3 = data[i + 2]; 133 134 out->append(encode6Bit(x1 >> 2)); 135 out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f)); 136 out->append(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f)); 137 out->append(encode6Bit(x3 & 0x3f)); 138 } 139 switch (size % 3) { 140 case 0: 141 break; 142 case 2: 143 { 144 uint8_t x1 = data[i]; 145 uint8_t x2 = data[i + 1]; 146 out->append(encode6Bit(x1 >> 2)); 147 out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f)); 148 out->append(encode6Bit((x2 << 2) & 0x3f)); 149 out->append('='); 150 break; 151 } 152 default: 153 { 154 uint8_t x1 = data[i]; 155 out->append(encode6Bit(x1 >> 2)); 156 out->append(encode6Bit((x1 << 4) & 0x3f)); 157 out->append("=="); 158 break; 159 } 160 } 161 } 162 163 void encodeBase64Url( 164 const void *_data, size_t size, AString *out) { 165 encodeBase64(_data, size, out); 166 167 if ((-1 != out->find("+")) || (-1 != out->find("/"))) { 168 size_t outLen = out->size(); 169 char *base64url = new char[outLen]; 170 for (size_t i = 0; i < outLen; ++i) { 171 if (out->c_str()[i] == '+') 172 base64url[i] = '-'; 173 else if (out->c_str()[i] == '/') 174 base64url[i] = '_'; 175 else 176 base64url[i] = out->c_str()[i]; 177 } 178 179 out->setTo(base64url, outLen); 180 delete[] base64url; 181 } 182 } 183 184 185 } // namespace android 186