aboutsummaryrefslogtreecommitdiff
path: root/libbutl
diff options
context:
space:
mode:
authorFrancois Kritzinger <francois@codesynthesis.com>2024-02-06 10:52:18 +0200
committerFrancois Kritzinger <francois@codesynthesis.com>2024-02-12 11:53:53 +0200
commit13ff1998e4003d109f4074bea42f78cb8de6ed91 (patch)
tree9750fddd018dc34d890461f871079d106e721079 /libbutl
parentd249dff880edd1520a979279934afc0a6370bd67 (diff)
Add base64url_encode()
Diffstat (limited to 'libbutl')
-rw-r--r--libbutl/base64.cxx76
-rw-r--r--libbutl/base64.hxx19
2 files changed, 86 insertions, 9 deletions
diff --git a/libbutl/base64.cxx b/libbutl/base64.cxx
index 4466f24..282f7c2 100644
--- a/libbutl/base64.cxx
+++ b/libbutl/base64.cxx
@@ -16,19 +16,20 @@ namespace butl
static const char codes[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ static const char codes_url[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
// base64-encode the data in the iterator range [i, e). Write the encoded
- // data starting at the iterator position o.
+ // data starting at the iterator position o. If url is true, encode using
+ // base64url.
//
template <typename I, typename O>
static void
- base64_encode (I& i, const I& e, O& o)
+ base64_encode (I& i, const I& e, O& o, bool url = false)
{
const size_t un (65); // Non-existing index of the codes string.
for (size_t n (0); i != e; ++n)
{
- if (n && n % 19 == 0)
- *o++ = '\n'; // Split into lines, like the base64 utility does.
-
auto next = [&i] () {return static_cast<unsigned char> (*i++);};
unsigned char c (next ());
@@ -51,10 +52,26 @@ namespace butl
i4 = c & 0x3F;
}
- *o++ = codes[i1];
- *o++ = codes[i2];
- *o++ = i3 == un ? '=' : codes[i3];
- *o++ = i4 == un ? '=' : codes[i4];
+ if (!url)
+ {
+ if (n && n % 19 == 0)
+ *o++ = '\n'; // Split into lines, like the base64 utility does.
+
+ *o++ = codes[i1];
+ *o++ = codes[i2];
+ *o++ = i3 == un ? '=' : codes[i3];
+ *o++ = i4 == un ? '=' : codes[i4];
+ }
+ // base64url: different 63rd and 64th characters and no padding or
+ // newlines.
+ //
+ else
+ {
+ *o++ = codes_url[i1];
+ *o++ = codes_url[i2];
+ if (i3 != un) *o++ = codes_url[i3];
+ if (i4 != un) *o++ = codes_url[i4];
+ }
}
}
@@ -170,6 +187,47 @@ namespace butl
return r;
}
+ string
+ base64url_encode (istream& is)
+ {
+ if (!is.good ())
+ throw invalid_argument ("bad stream");
+
+ string r;
+ istreambuf_iterator<char> i (is);
+ back_insert_iterator<string> o (r);
+
+ base64_encode (i, istreambuf_iterator<char> (), o, true /* url */);
+ is.setstate (istream::eofbit);
+ return r;
+ }
+
+ void
+ base64url_encode (ostream& os, istream& is)
+ {
+ if (!os.good () || !is.good ())
+ throw invalid_argument ("bad stream");
+
+ istreambuf_iterator<char> i (is);
+ ostreambuf_iterator<char> o (os);
+ base64_encode (i, istreambuf_iterator<char> (), o, true /* url */);
+
+ if (o.failed ())
+ os.setstate (istream::badbit);
+
+ is.setstate (istream::eofbit);
+ }
+
+ string
+ base64url_encode (const std::vector<char>& v)
+ {
+ string r;
+ back_insert_iterator<string> o (r);
+ auto i (v.begin ());
+ base64_encode (i, v.end (), o, true /* url */);
+ return r;
+ }
+
void
base64_decode (ostream& os, istream& is)
{
diff --git a/libbutl/base64.hxx b/libbutl/base64.hxx
index f38e62f..a0d1450 100644
--- a/libbutl/base64.hxx
+++ b/libbutl/base64.hxx
@@ -27,6 +27,25 @@ namespace butl
LIBBUTL_SYMEXPORT std::string
base64_encode (const std::vector<char>&);
+ // Encode a stream or a buffer using base64url (RFC4648), a base64 variant
+ // with different 62nd and 63rd alphabet characters (- and _ instead of ~
+ // and .; to make it filesystem safe) and optional padding because the
+ // padding character `=` would have to be percent-encoded to be safe in
+ // URLs. This implementation does not output any padding, newlines or any
+ // other whitespace (which is required, for example, by RFC7519: JSON Web
+ // Token (JWT) and RFC7515: JSON Web Signature (JWS)).
+ //
+ // Note that base64url decoding has not yet been implemented.
+ //
+ LIBBUTL_SYMEXPORT void
+ base64url_encode (std::ostream&, std::istream&);
+
+ LIBBUTL_SYMEXPORT std::string
+ base64url_encode (std::istream&);
+
+ LIBBUTL_SYMEXPORT std::string
+ base64url_encode (const std::vector<char>&);
+
// Base64-decode a stream or a string. Throw invalid_argument if the input
// is not a valid base64 representation. If reading from a stream, check if
// it has badbit, failbit, or eofbit set and throw invalid_argument if