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
decodeBase64(const AString & s)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
decodeBase64(uint8_t * out,size_t * inOutBufSize,const char * s)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
encode6Bit(unsigned x)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
encodeBase64(const void * _data,size_t size,AString * out)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
encodeBase64Url(const void * _data,size_t size,AString * out)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