mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 22:36:09 +03:00
154 lines
4.6 KiB
C++
154 lines
4.6 KiB
C++
// Copyright 2015 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "base/base64url.h"
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <string_view>
|
|
|
|
#include "base/base64.h"
|
|
#include "base/numerics/safe_math.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "third_party/modp_b64/modp_b64.h"
|
|
|
|
namespace base {
|
|
|
|
namespace {
|
|
|
|
const char kPaddingChar = '=';
|
|
|
|
// Base64url maps {+, /} to {-, _} in order for the encoded content to be safe
|
|
// to use in a URL. These characters will be translated by this implementation.
|
|
const char kBase64Chars[] = "+/";
|
|
const char kBase64UrlSafeChars[] = "-_";
|
|
|
|
class StringViewOrString {
|
|
public:
|
|
explicit StringViewOrString(std::string_view piece) : piece_(piece) {}
|
|
explicit StringViewOrString(std::string str) : str_(std::move(str)) {}
|
|
|
|
std::string_view get() const {
|
|
if (str_) {
|
|
return *str_;
|
|
}
|
|
return piece_;
|
|
}
|
|
|
|
private:
|
|
const std::optional<std::string> str_;
|
|
const std::string_view piece_;
|
|
};
|
|
|
|
// Converts the base64url `input` into a plain base64 string.
|
|
std::optional<StringViewOrString> Base64UrlToBase64(
|
|
std::string_view input,
|
|
Base64UrlDecodePolicy policy) {
|
|
// Characters outside of the base64url alphabet are disallowed, which includes
|
|
// the {+, /} characters found in the conventional base64 alphabet.
|
|
if (input.find_first_of(kBase64Chars) != std::string::npos)
|
|
return std::nullopt;
|
|
|
|
const size_t required_padding_characters = input.size() % 4;
|
|
const bool needs_replacement =
|
|
input.find_first_of(kBase64UrlSafeChars) != std::string::npos;
|
|
|
|
switch (policy) {
|
|
case Base64UrlDecodePolicy::REQUIRE_PADDING:
|
|
// Fail if the required padding is not included in |input|.
|
|
if (required_padding_characters > 0)
|
|
return std::nullopt;
|
|
break;
|
|
case Base64UrlDecodePolicy::IGNORE_PADDING:
|
|
// Missing padding will be silently appended.
|
|
break;
|
|
case Base64UrlDecodePolicy::DISALLOW_PADDING:
|
|
// Fail if padding characters are included in |input|.
|
|
if (input.find_first_of(kPaddingChar) != std::string::npos)
|
|
return std::nullopt;
|
|
break;
|
|
}
|
|
|
|
if (required_padding_characters == 0 && !needs_replacement) {
|
|
return StringViewOrString(input);
|
|
}
|
|
|
|
// If the string either needs replacement of URL-safe characters to normal
|
|
// base64 ones, or additional padding, a copy of |input| needs to be made in
|
|
// order to make these adjustments without side effects.
|
|
CheckedNumeric<size_t> out_size = input.size();
|
|
if (required_padding_characters > 0) {
|
|
out_size += 4 - required_padding_characters;
|
|
}
|
|
|
|
std::string base64_input;
|
|
base64_input.reserve(out_size.ValueOrDie());
|
|
base64_input.append(input);
|
|
|
|
// Substitute the base64url URL-safe characters to their base64 equivalents.
|
|
ReplaceChars(base64_input, "-", "+", &base64_input);
|
|
ReplaceChars(base64_input, "_", "/", &base64_input);
|
|
|
|
// Append the necessary padding characters.
|
|
base64_input.resize(out_size.ValueOrDie(), '=');
|
|
|
|
return StringViewOrString(std::move(base64_input));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void Base64UrlEncode(span<const uint8_t> input,
|
|
Base64UrlEncodePolicy policy,
|
|
std::string* output) {
|
|
*output = Base64Encode(input);
|
|
|
|
ReplaceChars(*output, "+", "-", output);
|
|
ReplaceChars(*output, "/", "_", output);
|
|
|
|
switch (policy) {
|
|
case Base64UrlEncodePolicy::INCLUDE_PADDING:
|
|
// The padding included in |*output| will not be amended.
|
|
break;
|
|
case Base64UrlEncodePolicy::OMIT_PADDING:
|
|
// The padding included in |*output| will be removed.
|
|
const size_t last_non_padding_pos =
|
|
output->find_last_not_of(kPaddingChar);
|
|
if (last_non_padding_pos != std::string::npos) {
|
|
output->resize(last_non_padding_pos + 1);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Base64UrlEncode(std::string_view input,
|
|
Base64UrlEncodePolicy policy,
|
|
std::string* output) {
|
|
Base64UrlEncode(base::as_byte_span(input), policy, output);
|
|
}
|
|
|
|
bool Base64UrlDecode(std::string_view input,
|
|
Base64UrlDecodePolicy policy,
|
|
std::string* output) {
|
|
std::optional<StringViewOrString> base64_input =
|
|
Base64UrlToBase64(input, policy);
|
|
if (!base64_input) {
|
|
return false;
|
|
}
|
|
return Base64Decode(base64_input->get(), output);
|
|
}
|
|
|
|
std::optional<std::vector<uint8_t>> Base64UrlDecode(
|
|
std::string_view input,
|
|
Base64UrlDecodePolicy policy) {
|
|
std::optional<StringViewOrString> base64_input =
|
|
Base64UrlToBase64(input, policy);
|
|
if (!base64_input) {
|
|
return std::nullopt;
|
|
}
|
|
return Base64Decode(base64_input->get());
|
|
}
|
|
|
|
} // namespace base
|