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