base64_test.cc
Go to the documentation of this file.
1 /* Copyright (c) 2014, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include <string>
19 #include <vector>
20 
21 #include <gtest/gtest.h>
22 
23 #include <openssl/base64.h>
24 #include <openssl/crypto.h>
25 #include <openssl/err.h>
26 
27 #include "../internal.h"
28 #include "../test/test_util.h"
29 
30 
32  // canonical indicates that the encoding is the expected encoding of the
33  // input.
35  // valid indicates that the encoding is /a/ valid encoding of the input, but
36  // need not be the canonical one.
38  // invalid indicates that the encoded data is valid.
40 };
41 
44  const char *decoded;
45  const char *encoded;
46 };
47 
48 // Test vectors from RFC 4648.
49 static const Base64TestVector kTestVectors[] = {
50  {canonical, "", ""},
51  {canonical, "f", "Zg==\n"},
52  {canonical, "fo", "Zm8=\n"},
53  {canonical, "foo", "Zm9v\n"},
54  {canonical, "foob", "Zm9vYg==\n"},
55  {canonical, "fooba", "Zm9vYmE=\n"},
56  {canonical, "foobar", "Zm9vYmFy\n"},
57  {valid, "foobar", "Zm9vYmFy\n\n"},
58  {valid, "foobar", " Zm9vYmFy\n\n"},
59  {valid, "foobar", " Z m 9 v Y m F y\n\n"},
60  {invalid, "", "Zm9vYmFy=\n"},
61  {invalid, "", "Zm9vYmFy==\n"},
62  {invalid, "", "Zm9vYmFy===\n"},
63  {invalid, "", "Z"},
64  {invalid, "", "Z\n"},
65  {invalid, "", "ab!c"},
66  {invalid, "", "ab=c"},
67  {invalid, "", "abc"},
68 
69  {canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
70  "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==\n"},
71  {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
72  "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA\n==\n"},
73  {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
74  "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n=\n"},
75  {invalid, "",
76  "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n==\n"},
77  {canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
78  "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
79  "4eHh4eHh4\n"},
80  {canonical,
81  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
82  "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
83  "4eHh4eHh4eHh4eA==\n"},
84  {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
85  "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh\n4eHh4eHh"
86  "4eHh4eHh4eHh4eA==\n"},
87  {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
88  "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e"
89  "Hh4eHh4eHh4eA==\n"},
90  {invalid, "",
91  "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=="
92  "\neHh4eHh4eHh4eHh4eHh4eHh4\n"},
93 
94  // A '-' has traditionally been treated as the end of the data by OpenSSL
95  // and anything following would be ignored. BoringSSL does not accept this
96  // non-standard extension.
97  {invalid, "", "Zm9vYmFy-anythinggoes"},
98  {invalid, "", "Zm9vYmFy\n-anythinggoes"},
99 
100  // CVE-2015-0292
101  {invalid, "",
102  "ZW5jb2RlIG1lCg==========================================================="
103  "=======\n"},
104 };
105 
106 class Base64Test : public testing::TestWithParam<Base64TestVector> {};
107 
109 
110 // RemoveNewlines returns a copy of |in| with all '\n' characters removed.
111 static std::string RemoveNewlines(const char *in) {
113  const size_t in_len = strlen(in);
114 
115  for (size_t i = 0; i < in_len; i++) {
116  if (in[i] != '\n') {
117  ret.push_back(in[i]);
118  }
119  }
120 
121  return ret;
122 }
123 
124 TEST_P(Base64Test, EncodeBlock) {
125  const Base64TestVector &t = GetParam();
126  if (t.relation != canonical) {
127  return;
128  }
129 
130  const size_t decoded_len = strlen(t.decoded);
131  size_t max_encoded_len;
132  ASSERT_TRUE(EVP_EncodedLength(&max_encoded_len, decoded_len));
133 
134  std::vector<uint8_t> out_vec(max_encoded_len);
135  uint8_t *out = out_vec.data();
136  size_t len = EVP_EncodeBlock(out, (const uint8_t *)t.decoded, decoded_len);
137 
138  std::string encoded(RemoveNewlines(t.encoded));
139  EXPECT_EQ(Bytes(encoded), Bytes(out, len));
140 }
141 
143  const Base64TestVector &t = GetParam();
144  if (t.relation == valid) {
145  // The non-canonical encodings will generally have odd whitespace etc
146  // that |EVP_DecodeBase64| will reject.
147  return;
148  }
149 
150  const std::string encoded(RemoveNewlines(t.encoded));
151  std::vector<uint8_t> out_vec(encoded.size());
152  uint8_t *out = out_vec.data();
153 
154  size_t len;
155  int ok = EVP_DecodeBase64(out, &len, out_vec.size(),
156  (const uint8_t *)encoded.data(), encoded.size());
157 
158  if (t.relation == invalid) {
159  EXPECT_FALSE(ok);
160  } else if (t.relation == canonical) {
161  ASSERT_TRUE(ok);
162  EXPECT_EQ(Bytes(t.decoded), Bytes(out, len));
163  }
164 }
165 
166 TEST_P(Base64Test, DecodeBlock) {
167  const Base64TestVector &t = GetParam();
168  if (t.relation != canonical) {
169  return;
170  }
171 
172  std::string encoded(RemoveNewlines(t.encoded));
173 
174  std::vector<uint8_t> out_vec(encoded.size());
175  uint8_t *out = out_vec.data();
176 
177  // Test that the padding behavior of the deprecated API is preserved.
178  int ret =
179  EVP_DecodeBlock(out, (const uint8_t *)encoded.data(), encoded.size());
180  ASSERT_GE(ret, 0);
181  // EVP_DecodeBlock should ignore padding.
182  ASSERT_EQ(0, ret % 3);
183  size_t expected_len = strlen(t.decoded);
184  if (expected_len % 3 != 0) {
185  ret -= 3 - (expected_len % 3);
186  }
187  EXPECT_EQ(Bytes(t.decoded), Bytes(out, static_cast<size_t>(ret)));
188 }
189 
190 TEST_P(Base64Test, EncodeDecode) {
191  const Base64TestVector &t = GetParam();
192 
194  const size_t decoded_len = strlen(t.decoded);
195 
196  if (t.relation == canonical) {
197  size_t max_encoded_len;
198  ASSERT_TRUE(EVP_EncodedLength(&max_encoded_len, decoded_len));
199 
200  // EVP_EncodeUpdate will output new lines every 64 bytes of output so we
201  // need slightly more than |EVP_EncodedLength| returns. */
202  max_encoded_len += (max_encoded_len + 63) >> 6;
203  std::vector<uint8_t> out_vec(max_encoded_len);
204  uint8_t *out = out_vec.data();
205 
207 
208  int out_len;
209  EVP_EncodeUpdate(&ctx, out, &out_len,
210  reinterpret_cast<const uint8_t *>(t.decoded),
211  decoded_len);
212  size_t total = out_len;
213 
214  EVP_EncodeFinal(&ctx, out + total, &out_len);
215  total += out_len;
216 
217  EXPECT_EQ(Bytes(t.encoded), Bytes(out, total));
218  }
219 
220  std::vector<uint8_t> out_vec(strlen(t.encoded));
221  uint8_t *out = out_vec.data();
222 
224  int out_len;
225  size_t total = 0;
226  int ret = EVP_DecodeUpdate(&ctx, out, &out_len,
227  reinterpret_cast<const uint8_t *>(t.encoded),
228  strlen(t.encoded));
229  if (ret != -1) {
230  total = out_len;
231  ret = EVP_DecodeFinal(&ctx, out + total, &out_len);
232  total += out_len;
233  }
234 
235  switch (t.relation) {
236  case canonical:
237  case valid:
238  ASSERT_NE(-1, ret);
239  EXPECT_EQ(Bytes(t.decoded), Bytes(out, total));
240  break;
241 
242  case invalid:
243  EXPECT_EQ(-1, ret);
244  break;
245  }
246 }
247 
248 TEST_P(Base64Test, DecodeUpdateStreaming) {
249  const Base64TestVector &t = GetParam();
250  if (t.relation == invalid) {
251  return;
252  }
253 
254  const size_t encoded_len = strlen(t.encoded);
255 
256  std::vector<uint8_t> out(encoded_len);
257 
258  for (size_t chunk_size = 1; chunk_size <= encoded_len; chunk_size++) {
259  SCOPED_TRACE(chunk_size);
260  size_t out_len = 0;
263 
264  for (size_t i = 0; i < encoded_len;) {
265  size_t todo = encoded_len - i;
266  if (todo > chunk_size) {
267  todo = chunk_size;
268  }
269 
270  int bytes_written;
271  int ret = EVP_DecodeUpdate(
272  &ctx, out.data() + out_len, &bytes_written,
273  reinterpret_cast<const uint8_t *>(t.encoded + i), todo);
274  i += todo;
275 
276  switch (ret) {
277  case -1:
278  FAIL() << "EVP_DecodeUpdate failed";
279  case 0:
280  out_len += bytes_written;
281  if (i == encoded_len ||
282  (i + 1 == encoded_len && t.encoded[i] == '\n') ||
283  // If there was an '-' in the input (which means “EOF”) then
284  // this loop will continue to test that |EVP_DecodeUpdate| will
285  // ignore the remainder of the input.
286  strchr(t.encoded, '-') != nullptr) {
287  break;
288  }
289 
290  FAIL()
291  << "EVP_DecodeUpdate returned zero before end of encoded data.";
292  case 1:
293  out_len += bytes_written;
294  break;
295  default:
296  FAIL() << "Invalid return value " << ret;
297  }
298  }
299 
300  int bytes_written;
301  int ret = EVP_DecodeFinal(&ctx, out.data() + out_len, &bytes_written);
302  ASSERT_NE(ret, -1);
303  out_len += bytes_written;
304 
305  EXPECT_EQ(Bytes(t.decoded), Bytes(out.data(), out_len));
306  }
307 }
EXPECT_FALSE
#define EXPECT_FALSE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1970
ASSERT_NE
#define ASSERT_NE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2060
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
Bytes
Definition: boringssl-with-bazel/src/crypto/test/test_util.h:38
ctx
Definition: benchmark-async.c:30
RemoveNewlines
static std::string RemoveNewlines(const char *in)
Definition: base64_test.cc:111
EVP_EncodedLength
#define EVP_EncodedLength
Definition: boringssl_prefix_symbols.h:1527
TEST_P
TEST_P(Base64Test, EncodeBlock)
Definition: base64_test.cc:124
total
size_t total
Definition: cord_analysis.cc:59
string.h
EVP_DecodeUpdate
#define EVP_DecodeUpdate
Definition: boringssl_prefix_symbols.h:1499
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
ASSERT_GE
#define ASSERT_GE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2072
ctx
static struct test_ctx ctx
Definition: test-ipc-send-recv.c:65
EVP_DecodeBlock
#define EVP_DecodeBlock
Definition: boringssl_prefix_symbols.h:1496
EVP_EncodeFinal
#define EVP_EncodeFinal
Definition: boringssl_prefix_symbols.h:1524
Base64TestVector::decoded
const char * decoded
Definition: base64_test.cc:44
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
testing::TestWithParam
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1883
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: iomgr/time_averaged_stats_test.cc:27
INSTANTIATE_TEST_SUITE_P
INSTANTIATE_TEST_SUITE_P(All, Base64Test, testing::ValuesIn(kTestVectors))
EVP_DecodeFinal
#define EVP_DecodeFinal
Definition: boringssl_prefix_symbols.h:1497
canonical
@ canonical
Definition: base64_test.cc:34
in
const char * in
Definition: third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc:391
SCOPED_TRACE
#define SCOPED_TRACE(message)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2264
invalid
@ invalid
Definition: base64_test.cc:39
EVP_EncodeInit
#define EVP_EncodeInit
Definition: boringssl_prefix_symbols.h:1525
EVP_DecodeBase64
#define EVP_DecodeBase64
Definition: boringssl_prefix_symbols.h:1495
err.h
crypto.h
valid
@ valid
Definition: base64_test.cc:37
FAIL
@ FAIL
Definition: call_creds.cc:42
base64.h
Base64TestVector::relation
enum encoding_relation relation
Definition: base64_test.cc:43
Base64TestVector::encoded
const char * encoded
Definition: base64_test.cc:45
kTestVectors
static const Base64TestVector kTestVectors[]
Definition: base64_test.cc:49
EVP_EncodeBlock
#define EVP_EncodeBlock
Definition: boringssl_prefix_symbols.h:1523
evp_encode_ctx_st
Definition: base64.h:177
BSSL_NAMESPACE_BEGIN::DecodeBase64
static bool DecodeBase64(std::vector< uint8_t > *out, const char *in)
Definition: ssl_test.cc:795
EVP_DecodeInit
#define EVP_DecodeInit
Definition: boringssl_prefix_symbols.h:1498
Base64TestVector
Definition: base64_test.cc:42
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
ASSERT_TRUE
#define ASSERT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1973
ok
bool ok
Definition: async_end2end_test.cc:197
encoding_relation
encoding_relation
Definition: base64_test.cc:31
bytes_written
static size_t bytes_written
Definition: test-ipc-heavy-traffic-deadlock-bug.c:46
testing::ValuesIn
internal::ParamGenerator< typename std::iterator_traits< ForwardIterator >::value_type > ValuesIn(ForwardIterator begin, ForwardIterator end)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:297
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
EVP_EncodeUpdate
#define EVP_EncodeUpdate
Definition: boringssl_prefix_symbols.h:1526
mkowners.todo
todo
Definition: mkowners.py:209
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
Base64Test
Definition: base64_test.cc:106
ASSERT_EQ
#define ASSERT_EQ(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2056


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:45