| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/base64url.h" |
| |
| #include "base/base64.h" |
| #include "base/numerics/safe_math.h" |
| #include "base/strings/string_util.h" |
| #include "third_party/modp_b64/modp_b64.h" |
| |
| namespace base { |
| |
| const char kPaddingChar = '='; |
| |
| // Base64url maps {+, /} to {-, _} in order for the encoded content to be safe |
| // to use in a URL. These characters will be translated by this implementation. |
| const char kBase64Chars[] = "+/"; |
| const char kBase64UrlSafeChars[] = "-_"; |
| |
| void Base64UrlEncode(const StringPiece& input, |
| Base64UrlEncodePolicy policy, |
| std::string* output) { |
| Base64Encode(input, output); |
| |
| ReplaceChars(*output, "+", "-", output); |
| ReplaceChars(*output, "/", "_", output); |
| |
| switch (policy) { |
| case Base64UrlEncodePolicy::INCLUDE_PADDING: |
| // The padding included in |*output| will not be amended. |
| break; |
| case Base64UrlEncodePolicy::OMIT_PADDING: |
| // The padding included in |*output| will be removed. |
| const size_t last_non_padding_pos = |
| output->find_last_not_of(kPaddingChar); |
| if (last_non_padding_pos != std::string::npos) |
| output->resize(last_non_padding_pos + 1); |
| |
| break; |
| } |
| } |
| |
| bool Base64UrlDecode(const StringPiece& input, |
| Base64UrlDecodePolicy policy, |
| std::string* output) { |
| // Characters outside of the base64url alphabet are disallowed, which includes |
| // the {+, /} characters found in the conventional base64 alphabet. |
| if (input.find_first_of(kBase64Chars) != std::string::npos) |
| return false; |
| |
| const size_t required_padding_characters = input.size() % 4; |
| const bool needs_replacement = |
| input.find_first_of(kBase64UrlSafeChars) != std::string::npos; |
| |
| switch (policy) { |
| case Base64UrlDecodePolicy::REQUIRE_PADDING: |
| // Fail if the required padding is not included in |input|. |
| if (required_padding_characters > 0) |
| return false; |
| break; |
| case Base64UrlDecodePolicy::IGNORE_PADDING: |
| // Missing padding will be silently appended. |
| break; |
| case Base64UrlDecodePolicy::DISALLOW_PADDING: |
| // Fail if padding characters are included in |input|. |
| if (input.find_first_of(kPaddingChar) != std::string::npos) |
| return false; |
| break; |
| } |
| |
| // If the string either needs replacement of URL-safe characters to normal |
| // base64 ones, or additional padding, a copy of |input| needs to be made in |
| // order to make these adjustments without side effects. |
| if (required_padding_characters > 0 || needs_replacement) { |
| std::string base64_input; |
| |
| CheckedNumeric<size_t> base64_input_size = input.size(); |
| if (required_padding_characters > 0) |
| base64_input_size += 4 - required_padding_characters; |
| |
| base64_input.reserve(base64_input_size.ValueOrDie()); |
| input.AppendToString(&base64_input); |
| |
| // Substitute the base64url URL-safe characters to their base64 equivalents. |
| ReplaceChars(base64_input, "-", "+", &base64_input); |
| ReplaceChars(base64_input, "_", "/", &base64_input); |
| |
| // Append the necessary padding characters. |
| base64_input.resize(base64_input_size.ValueOrDie(), '='); |
| |
| return Base64Decode(base64_input, output); |
| } |
| |
| return Base64Decode(input, output); |
| } |
| |
| } // namespace base |