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