base64url.cc 3.4 KB

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