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     if ((n % 4) != 0) {
27         return NULL;
28     }
29 
30     size_t padding = 0;
31     if (n >= 1 && s.c_str()[n - 1] == '=') {
32         padding = 1;
33 
34         if (n >= 2 && s.c_str()[n - 2] == '=') {
35             padding = 2;
36 
37             if (n >= 3 && s.c_str()[n - 3] == '=') {
38                 padding = 3;
39             }
40         }
41     }
42 
43     // We divide first to avoid overflow. It's OK to do this because we
44     // already made sure that n % 4 == 0.
45     size_t outLen = (n / 4) * 3 - padding;
46 
47     sp<ABuffer> buffer = new ABuffer(outLen);
48 
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 == '+') {
65             value = 62;
66         } else if (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             out[j++] = (accum >> 16);
82 
83             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
84             if (j < outLen) { out[j++] = accum & 0xff; }
85 
86             accum = 0;
87         }
88     }
89 
90     return buffer;
91 }
92 
encode6Bit(unsigned x)93 static char encode6Bit(unsigned x) {
94     if (x <= 25) {
95         return 'A' + x;
96     } else if (x <= 51) {
97         return 'a' + x - 26;
98     } else if (x <= 61) {
99         return '0' + x - 52;
100     } else if (x == 62) {
101         return '+';
102     } else {
103         return '/';
104     }
105 }
106 
encodeBase64(const void * _data,size_t size,AString * out)107 void encodeBase64(
108         const void *_data, size_t size, AString *out) {
109     out->clear();
110 
111     const uint8_t *data = (const uint8_t *)_data;
112 
113     size_t i;
114     for (i = 0; i < (size / 3) * 3; i += 3) {
115         uint8_t x1 = data[i];
116         uint8_t x2 = data[i + 1];
117         uint8_t x3 = data[i + 2];
118 
119         out->append(encode6Bit(x1 >> 2));
120         out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
121         out->append(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f));
122         out->append(encode6Bit(x3 & 0x3f));
123     }
124     switch (size % 3) {
125         case 0:
126             break;
127         case 2:
128         {
129             uint8_t x1 = data[i];
130             uint8_t x2 = data[i + 1];
131             out->append(encode6Bit(x1 >> 2));
132             out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
133             out->append(encode6Bit((x2 << 2) & 0x3f));
134             out->append('=');
135             break;
136         }
137         default:
138         {
139             uint8_t x1 = data[i];
140             out->append(encode6Bit(x1 >> 2));
141             out->append(encode6Bit((x1 << 4) & 0x3f));
142             out->append("==");
143             break;
144         }
145     }
146 }
147 
148 }  // namespace android
149