1 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/base64url.h" 6 7 #include <stddef.h> 8 9 #include "base/base64.h" 10 #include "base/macros.h" 11 #include "base/numerics/safe_math.h" 12 #include "base/strings/string_util.h" 13 #include "third_party/modp_b64/modp_b64.h" 14 15 namespace base { 16 17 const char kPaddingChar = '='; 18 19 // Base64url maps {+, /} to {-, _} in order for the encoded content to be safe 20 // to use in a URL. These characters will be translated by this implementation. 21 const char kBase64Chars[] = "+/"; 22 const char kBase64UrlSafeChars[] = "-_"; 23 24 void Base64UrlEncode(const StringPiece& input, 25 Base64UrlEncodePolicy policy, 26 std::string* output) { 27 Base64Encode(input, output); 28 29 ReplaceChars(*output, "+", "-", output); 30 ReplaceChars(*output, "/", "_", output); 31 32 switch (policy) { 33 case Base64UrlEncodePolicy::INCLUDE_PADDING: 34 // The padding included in |*output| will not be amended. 35 break; 36 case Base64UrlEncodePolicy::OMIT_PADDING: 37 // The padding included in |*output| will be removed. 38 const size_t last_non_padding_pos = 39 output->find_last_not_of(kPaddingChar); 40 if (last_non_padding_pos != std::string::npos) 41 output->resize(last_non_padding_pos + 1); 42 43 break; 44 } 45 } 46 47 bool Base64UrlDecode(const StringPiece& input, 48 Base64UrlDecodePolicy policy, 49 std::string* output) { 50 // Characters outside of the base64url alphabet are disallowed, which includes 51 // the {+, /} characters found in the conventional base64 alphabet. 52 if (input.find_first_of(kBase64Chars) != std::string::npos) 53 return false; 54 55 const size_t required_padding_characters = input.size() % 4; 56 const bool needs_replacement = 57 input.find_first_of(kBase64UrlSafeChars) != std::string::npos; 58 59 switch (policy) { 60 case Base64UrlDecodePolicy::REQUIRE_PADDING: 61 // Fail if the required padding is not included in |input|. 62 if (required_padding_characters > 0) 63 return false; 64 break; 65 case Base64UrlDecodePolicy::IGNORE_PADDING: 66 // Missing padding will be silently appended. 67 break; 68 case Base64UrlDecodePolicy::DISALLOW_PADDING: 69 // Fail if padding characters are included in |input|. 70 if (input.find_first_of(kPaddingChar) != std::string::npos) 71 return false; 72 break; 73 } 74 75 // If the string either needs replacement of URL-safe characters to normal 76 // base64 ones, or additional padding, a copy of |input| needs to be made in 77 // order to make these adjustments without side effects. 78 if (required_padding_characters > 0 || needs_replacement) { 79 std::string base64_input; 80 81 CheckedNumeric<size_t> base64_input_size = input.size(); 82 if (required_padding_characters > 0) 83 base64_input_size += 4 - required_padding_characters; 84 85 base64_input.reserve(base64_input_size.ValueOrDie()); 86 input.AppendToString(&base64_input); 87 88 // Substitute the base64url URL-safe characters to their base64 equivalents. 89 ReplaceChars(base64_input, "-", "+", &base64_input); 90 ReplaceChars(base64_input, "_", "/", &base64_input); 91 92 // Append the necessary padding characters. 93 base64_input.resize(base64_input_size.ValueOrDie(), '='); 94 95 return Base64Decode(base64_input, output); 96 } 97 98 return Base64Decode(input, output); 99 } 100 101 } // namespace base 102