1 // Copyright 2015 The Chromium Authors
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 <string_view>
8
9 #include "base/ranges/algorithm.h"
10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12
13 using testing::ElementsAreArray;
14 using testing::Optional;
15
16 namespace base {
17
18 namespace {
19
TEST(Base64UrlTest,BinaryIncludePaddingPolicy)20 TEST(Base64UrlTest, BinaryIncludePaddingPolicy) {
21 const uint8_t kData[] = {0x00, 0x01, 0xFE, 0xFF};
22
23 std::string binary_encoded_with_padding;
24 Base64UrlEncode(kData, Base64UrlEncodePolicy::INCLUDE_PADDING,
25 &binary_encoded_with_padding);
26
27 // Check that encoding the same binary data through the std::string_view
28 // interface gives the same result.
29 std::string string_encoded_with_padding;
30 Base64UrlEncode(
31 std::string_view(reinterpret_cast<const char*>(kData), sizeof(kData)),
32 Base64UrlEncodePolicy::INCLUDE_PADDING, &string_encoded_with_padding);
33 EXPECT_EQ(binary_encoded_with_padding, string_encoded_with_padding);
34
35 // Check that decoding the result gives the same binary data.
36 EXPECT_THAT(Base64UrlDecode(string_encoded_with_padding,
37 Base64UrlDecodePolicy::REQUIRE_PADDING),
38 Optional(ElementsAreArray(kData)));
39
40 EXPECT_THAT(Base64UrlDecode(string_encoded_with_padding,
41 Base64UrlDecodePolicy::IGNORE_PADDING),
42 Optional(ElementsAreArray(kData)));
43
44 EXPECT_THAT(Base64UrlDecode(string_encoded_with_padding,
45 Base64UrlDecodePolicy::DISALLOW_PADDING),
46 std::nullopt);
47 }
48
TEST(Base64UrlTest,BinaryOmitPaddingPolicy)49 TEST(Base64UrlTest, BinaryOmitPaddingPolicy) {
50 const uint8_t kData[] = {0x00, 0x01, 0xFE, 0xFF};
51
52 std::string binary_encoded_without_padding;
53 Base64UrlEncode(kData, Base64UrlEncodePolicy::OMIT_PADDING,
54 &binary_encoded_without_padding);
55
56 // Check that encoding the same binary data through the std::string_view
57 // interface gives the same result.
58 std::string string_encoded_without_padding;
59 Base64UrlEncode(
60 std::string_view(reinterpret_cast<const char*>(kData), sizeof(kData)),
61 Base64UrlEncodePolicy::OMIT_PADDING, &string_encoded_without_padding);
62 EXPECT_EQ(binary_encoded_without_padding, string_encoded_without_padding);
63
64 // Check that decoding the result gives the same binary data.
65 EXPECT_THAT(Base64UrlDecode(string_encoded_without_padding,
66 Base64UrlDecodePolicy::DISALLOW_PADDING),
67 Optional(ElementsAreArray(kData)));
68
69 EXPECT_THAT(Base64UrlDecode(string_encoded_without_padding,
70 Base64UrlDecodePolicy::IGNORE_PADDING),
71 Optional(ElementsAreArray(kData)));
72
73 EXPECT_THAT(Base64UrlDecode(string_encoded_without_padding,
74 Base64UrlDecodePolicy::REQUIRE_PADDING),
75 std::nullopt);
76 }
77
TEST(Base64UrlTest,EncodeIncludePaddingPolicy)78 TEST(Base64UrlTest, EncodeIncludePaddingPolicy) {
79 std::string output;
80 Base64UrlEncode("hello?world", Base64UrlEncodePolicy::INCLUDE_PADDING,
81 &output);
82
83 // Base64 version: aGVsbG8/d29ybGQ=
84 EXPECT_EQ("aGVsbG8_d29ybGQ=", output);
85
86 // Test for behavior for very short and empty strings.
87 Base64UrlEncode("??", Base64UrlEncodePolicy::INCLUDE_PADDING, &output);
88 EXPECT_EQ("Pz8=", output);
89
90 Base64UrlEncode("", Base64UrlEncodePolicy::INCLUDE_PADDING, &output);
91 EXPECT_EQ("", output);
92 }
93
TEST(Base64UrlTest,EncodeOmitPaddingPolicy)94 TEST(Base64UrlTest, EncodeOmitPaddingPolicy) {
95 std::string output;
96 Base64UrlEncode("hello?world", Base64UrlEncodePolicy::OMIT_PADDING, &output);
97
98 // base64 version: aGVsbG8/d29ybGQ=
99 EXPECT_EQ("aGVsbG8_d29ybGQ", output);
100
101 // Test for behavior for very short and empty strings.
102 Base64UrlEncode("??", Base64UrlEncodePolicy::OMIT_PADDING, &output);
103 EXPECT_EQ("Pz8", output);
104
105 Base64UrlEncode("", Base64UrlEncodePolicy::OMIT_PADDING, &output);
106 EXPECT_EQ("", output);
107 }
108
TEST(Base64UrlTest,EncodeInPlaceOmitPaddingPolicy)109 TEST(Base64UrlTest, EncodeInPlaceOmitPaddingPolicy) {
110 std::string input = "hello?world";
111 Base64UrlEncode(input, Base64UrlEncodePolicy::OMIT_PADDING, &input);
112 EXPECT_EQ("aGVsbG8_d29ybGQ", input);
113 }
114
TEST(Base64UrlTest,EncodeInPlaceIncludePaddingPolicy)115 TEST(Base64UrlTest, EncodeInPlaceIncludePaddingPolicy) {
116 std::string input = "hello?world";
117 Base64UrlEncode(input, Base64UrlEncodePolicy::INCLUDE_PADDING, &input);
118 EXPECT_EQ("aGVsbG8_d29ybGQ=", input);
119 }
120
TEST(Base64UrlTest,DecodeRequirePaddingPolicy)121 TEST(Base64UrlTest, DecodeRequirePaddingPolicy) {
122 std::string output;
123 ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=",
124 Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
125
126 EXPECT_EQ("hello?world", output);
127
128 ASSERT_FALSE(Base64UrlDecode(
129 "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
130
131 // Test for behavior for very short and empty strings.
132 ASSERT_TRUE(
133 Base64UrlDecode("Pz8=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
134 EXPECT_EQ("??", output);
135
136 ASSERT_TRUE(
137 Base64UrlDecode("", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
138 EXPECT_EQ("", output);
139 }
140
TEST(Base64UrlTest,DecodeIgnorePaddingPolicy)141 TEST(Base64UrlTest, DecodeIgnorePaddingPolicy) {
142 std::string output;
143 ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ",
144 Base64UrlDecodePolicy::IGNORE_PADDING, &output));
145
146 EXPECT_EQ("hello?world", output);
147
148 // Including the padding is accepted as well.
149 ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=",
150 Base64UrlDecodePolicy::IGNORE_PADDING, &output));
151
152 EXPECT_EQ("hello?world", output);
153 }
154
TEST(Base64UrlTest,DecodeIntoVector)155 TEST(Base64UrlTest, DecodeIntoVector) {
156 ASSERT_FALSE(
157 Base64UrlDecode("invalid=", Base64UrlDecodePolicy::DISALLOW_PADDING));
158
159 static constexpr uint8_t kExpected[] = {'1', '2', '3', '4'};
160 std::optional<std::vector<uint8_t>> result =
161 Base64UrlDecode("MTIzNA", Base64UrlDecodePolicy::DISALLOW_PADDING);
162 ASSERT_TRUE(ranges::equal(*result, kExpected));
163 }
164
TEST(Base64UrlTest,DecodeDisallowPaddingPolicy)165 TEST(Base64UrlTest, DecodeDisallowPaddingPolicy) {
166 std::string output;
167 ASSERT_FALSE(Base64UrlDecode(
168 "aGVsbG8_d29ybGQ=", Base64UrlDecodePolicy::DISALLOW_PADDING, &output));
169
170 // The policy will allow the input when padding has been omitted.
171 ASSERT_TRUE(Base64UrlDecode(
172 "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::DISALLOW_PADDING, &output));
173
174 EXPECT_EQ("hello?world", output);
175 }
176
TEST(Base64UrlTest,DecodeDisallowsBase64Alphabet)177 TEST(Base64UrlTest, DecodeDisallowsBase64Alphabet) {
178 std::string output;
179
180 // The "/" character is part of the conventional base64 alphabet, but has been
181 // substituted with "_" in the base64url alphabet.
182 ASSERT_FALSE(Base64UrlDecode(
183 "aGVsbG8/d29ybGQ=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
184 }
185
TEST(Base64UrlTest,DecodeDisallowsPaddingOnly)186 TEST(Base64UrlTest, DecodeDisallowsPaddingOnly) {
187 std::string output;
188
189 ASSERT_FALSE(Base64UrlDecode(
190 "=", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
191 ASSERT_FALSE(Base64UrlDecode(
192 "==", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
193 ASSERT_FALSE(Base64UrlDecode(
194 "===", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
195 ASSERT_FALSE(Base64UrlDecode(
196 "====", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
197 }
198
199 } // namespace
200
201 } // namespace base
202