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