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
Base64UrlEncode(const StringPiece & input,Base64UrlEncodePolicy policy,std::string * output)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
Base64UrlDecode(const StringPiece & input,Base64UrlDecodePolicy policy,std::string * output)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