xref: /aosp_15_r20/external/libbrillo/brillo/data_encoding.cc (revision 1a96fba65179ea7d3f56207137718607415c5953)
1*1a96fba6SXin Li // Copyright 2014 The Chromium OS Authors. All rights reserved.
2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be
3*1a96fba6SXin Li // found in the LICENSE file.
4*1a96fba6SXin Li 
5*1a96fba6SXin Li #include <brillo/data_encoding.h>
6*1a96fba6SXin Li #include <modp_b64/modp_b64.h>
7*1a96fba6SXin Li 
8*1a96fba6SXin Li #include <memory>
9*1a96fba6SXin Li 
10*1a96fba6SXin Li #include <base/logging.h>
11*1a96fba6SXin Li #include <base/strings/string_util.h>
12*1a96fba6SXin Li #include <base/strings/stringprintf.h>
13*1a96fba6SXin Li #include <brillo/strings/string_utils.h>
14*1a96fba6SXin Li 
15*1a96fba6SXin Li namespace {
16*1a96fba6SXin Li 
HexToDec(int hex)17*1a96fba6SXin Li inline int HexToDec(int hex) {
18*1a96fba6SXin Li   int dec = -1;
19*1a96fba6SXin Li   if (hex >= '0' && hex <= '9') {
20*1a96fba6SXin Li     dec = hex - '0';
21*1a96fba6SXin Li   } else if (hex >= 'A' && hex <= 'F') {
22*1a96fba6SXin Li     dec = hex - 'A' + 10;
23*1a96fba6SXin Li   } else if (hex >= 'a' && hex <= 'f') {
24*1a96fba6SXin Li     dec = hex - 'a' + 10;
25*1a96fba6SXin Li   }
26*1a96fba6SXin Li   return dec;
27*1a96fba6SXin Li }
28*1a96fba6SXin Li 
29*1a96fba6SXin Li // Helper for Base64Encode() and Base64EncodeWrapLines().
Base64EncodeHelper(const void * data,size_t size)30*1a96fba6SXin Li std::string Base64EncodeHelper(const void* data, size_t size) {
31*1a96fba6SXin Li   std::vector<char> buffer;
32*1a96fba6SXin Li   buffer.resize(modp_b64_encode_len(size));
33*1a96fba6SXin Li   size_t out_size = modp_b64_encode(buffer.data(),
34*1a96fba6SXin Li                                     static_cast<const char*>(data),
35*1a96fba6SXin Li                                     size);
36*1a96fba6SXin Li   return std::string{buffer.begin(), buffer.begin() + out_size};
37*1a96fba6SXin Li }
38*1a96fba6SXin Li 
39*1a96fba6SXin Li }  // namespace
40*1a96fba6SXin Li 
41*1a96fba6SXin Li /////////////////////////////////////////////////////////////////////////
42*1a96fba6SXin Li namespace brillo {
43*1a96fba6SXin Li namespace data_encoding {
44*1a96fba6SXin Li 
UrlEncode(const char * data,bool encodeSpaceAsPlus)45*1a96fba6SXin Li std::string UrlEncode(const char* data, bool encodeSpaceAsPlus) {
46*1a96fba6SXin Li   std::string result;
47*1a96fba6SXin Li 
48*1a96fba6SXin Li   while (*data) {
49*1a96fba6SXin Li     char c = *data++;
50*1a96fba6SXin Li     // According to RFC3986 (http://www.faqs.org/rfcs/rfc3986.html),
51*1a96fba6SXin Li     // section 2.3. - Unreserved Characters
52*1a96fba6SXin Li     if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
53*1a96fba6SXin Li         (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' ||
54*1a96fba6SXin Li         c == '~') {
55*1a96fba6SXin Li       result += c;
56*1a96fba6SXin Li     } else if (c == ' ' && encodeSpaceAsPlus) {
57*1a96fba6SXin Li       // For historical reasons, some URLs have spaces encoded as '+',
58*1a96fba6SXin Li       // this also applies to form data encoded as
59*1a96fba6SXin Li       // 'application/x-www-form-urlencoded'
60*1a96fba6SXin Li       result += '+';
61*1a96fba6SXin Li     } else {
62*1a96fba6SXin Li       base::StringAppendF(&result,
63*1a96fba6SXin Li                           "%%%02X",
64*1a96fba6SXin Li                           static_cast<unsigned char>(c));  // Encode as %NN
65*1a96fba6SXin Li     }
66*1a96fba6SXin Li   }
67*1a96fba6SXin Li   return result;
68*1a96fba6SXin Li }
69*1a96fba6SXin Li 
UrlDecode(const char * data)70*1a96fba6SXin Li std::string UrlDecode(const char* data) {
71*1a96fba6SXin Li   std::string result;
72*1a96fba6SXin Li   while (*data) {
73*1a96fba6SXin Li     char c = *data++;
74*1a96fba6SXin Li     int part1 = 0, part2 = 0;
75*1a96fba6SXin Li     // HexToDec would return -1 even for character 0 (end of string),
76*1a96fba6SXin Li     // so it is safe to access data[0] and data[1] without overrunning the buf.
77*1a96fba6SXin Li     if (c == '%' && (part1 = HexToDec(data[0])) >= 0 &&
78*1a96fba6SXin Li         (part2 = HexToDec(data[1])) >= 0) {
79*1a96fba6SXin Li       c = static_cast<char>((part1 << 4) | part2);
80*1a96fba6SXin Li       data += 2;
81*1a96fba6SXin Li     } else if (c == '+') {
82*1a96fba6SXin Li       c = ' ';
83*1a96fba6SXin Li     }
84*1a96fba6SXin Li     result += c;
85*1a96fba6SXin Li   }
86*1a96fba6SXin Li   return result;
87*1a96fba6SXin Li }
88*1a96fba6SXin Li 
WebParamsEncode(const WebParamList & params,bool encodeSpaceAsPlus)89*1a96fba6SXin Li std::string WebParamsEncode(const WebParamList& params,
90*1a96fba6SXin Li                             bool encodeSpaceAsPlus) {
91*1a96fba6SXin Li   std::vector<std::string> pairs;
92*1a96fba6SXin Li   pairs.reserve(params.size());
93*1a96fba6SXin Li   for (const auto& p : params) {
94*1a96fba6SXin Li     std::string key = UrlEncode(p.first.c_str(), encodeSpaceAsPlus);
95*1a96fba6SXin Li     std::string value = UrlEncode(p.second.c_str(), encodeSpaceAsPlus);
96*1a96fba6SXin Li     pairs.push_back(brillo::string_utils::Join("=", key, value));
97*1a96fba6SXin Li   }
98*1a96fba6SXin Li 
99*1a96fba6SXin Li   return brillo::string_utils::Join("&", pairs);
100*1a96fba6SXin Li }
101*1a96fba6SXin Li 
WebParamsDecode(const std::string & data)102*1a96fba6SXin Li WebParamList WebParamsDecode(const std::string& data) {
103*1a96fba6SXin Li   WebParamList result;
104*1a96fba6SXin Li   std::vector<std::string> params = brillo::string_utils::Split(data, "&");
105*1a96fba6SXin Li   for (const auto& p : params) {
106*1a96fba6SXin Li     auto pair = brillo::string_utils::SplitAtFirst(p, "=");
107*1a96fba6SXin Li     result.emplace_back(UrlDecode(pair.first.c_str()),
108*1a96fba6SXin Li                         UrlDecode(pair.second.c_str()));
109*1a96fba6SXin Li   }
110*1a96fba6SXin Li   return result;
111*1a96fba6SXin Li }
112*1a96fba6SXin Li 
Base64Encode(const void * data,size_t size)113*1a96fba6SXin Li std::string Base64Encode(const void* data, size_t size) {
114*1a96fba6SXin Li   return Base64EncodeHelper(data, size);
115*1a96fba6SXin Li }
116*1a96fba6SXin Li 
Base64EncodeWrapLines(const void * data,size_t size)117*1a96fba6SXin Li std::string Base64EncodeWrapLines(const void* data, size_t size) {
118*1a96fba6SXin Li   std::string unwrapped = Base64EncodeHelper(data, size);
119*1a96fba6SXin Li   std::string wrapped;
120*1a96fba6SXin Li 
121*1a96fba6SXin Li   for (size_t i = 0; i < unwrapped.size(); i += 64) {
122*1a96fba6SXin Li     wrapped.append(unwrapped, i, 64);
123*1a96fba6SXin Li     wrapped.append("\n");
124*1a96fba6SXin Li   }
125*1a96fba6SXin Li   return wrapped;
126*1a96fba6SXin Li }
127*1a96fba6SXin Li 
Base64Decode(const std::string & input,brillo::Blob * output)128*1a96fba6SXin Li bool Base64Decode(const std::string& input, brillo::Blob* output) {
129*1a96fba6SXin Li   std::string temp_buffer;
130*1a96fba6SXin Li   const std::string* data = &input;
131*1a96fba6SXin Li   if (input.find_first_of("\r\n") != std::string::npos) {
132*1a96fba6SXin Li     base::ReplaceChars(input, "\n", "", &temp_buffer);
133*1a96fba6SXin Li     base::ReplaceChars(temp_buffer, "\r", "", &temp_buffer);
134*1a96fba6SXin Li     data = &temp_buffer;
135*1a96fba6SXin Li   }
136*1a96fba6SXin Li   // base64 decoded data has 25% fewer bytes than the original (since every
137*1a96fba6SXin Li   // 3 source octets are encoded as 4 characters in base64).
138*1a96fba6SXin Li   // modp_b64_decode_len provides an upper estimate of the size of the output
139*1a96fba6SXin Li   // data.
140*1a96fba6SXin Li   output->resize(modp_b64_decode_len(data->size()));
141*1a96fba6SXin Li 
142*1a96fba6SXin Li   size_t size_read = modp_b64_decode(reinterpret_cast<char*>(output->data()),
143*1a96fba6SXin Li                                      data->data(), data->size());
144*1a96fba6SXin Li   if (size_read == MODP_B64_ERROR) {
145*1a96fba6SXin Li     output->resize(0);
146*1a96fba6SXin Li     return false;
147*1a96fba6SXin Li   }
148*1a96fba6SXin Li   output->resize(size_read);
149*1a96fba6SXin Li 
150*1a96fba6SXin Li   return true;
151*1a96fba6SXin Li }
152*1a96fba6SXin Li 
153*1a96fba6SXin Li }  // namespace data_encoding
154*1a96fba6SXin Li }  // namespace brillo
155