coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] basenc: Paddingless input/output for base64url


From: Imre Rad
Subject: [PATCH] basenc: Paddingless input/output for base64url
Date: Tue, 23 Aug 2022 10:43:22 +0200

* src/basenc.c (ignore-padding):
Padding is optional for base64url encoding and many web
services produce and expect payload without padding.
New command line argument (--ignore-padding) for basenc
allows generating paddingless base64url outputs and
you can also use it for decoding without scary
warnings on stderr.
* tests/local.mk (reference to new test):
Reference to the new test.
* tests/misc/basenc-padding.sh (new test):
Tests covering the new feature.
---
 src/basenc.c                 | 48 ++++++++++++++++----
 tests/local.mk               |  1 +
 tests/misc/basenc-padding.sh | 86 ++++++++++++++++++++++++++++++++++++
 3 files changed, 127 insertions(+), 8 deletions(-)
 create mode 100755 tests/misc/basenc-padding.sh

diff --git a/src/basenc.c b/src/basenc.c
index 04857d59e..9b020eccb 100644
--- a/src/basenc.c
+++ b/src/basenc.c
@@ -68,7 +68,8 @@ enum
   BASE16_OPTION,
   BASE2MSBF_OPTION,
   BASE2LSBF_OPTION,
-  Z85_OPTION
+  Z85_OPTION,
+  IGNORE_PADDING_OPTION
 };
 #endif

@@ -78,6 +79,7 @@ static struct option const long_options[] =
   {"wrap", required_argument, 0, 'w'},
   {"ignore-garbage", no_argument, 0, 'i'},
 #if BASE_TYPE == 42
+  {"ignore-padding", no_argument, 0, IGNORE_PADDING_OPTION},
   {"base64",    no_argument, 0, BASE64_OPTION},
   {"base64url", no_argument, 0, BASE64URL_OPTION},
   {"base32",    no_argument, 0, BASE32_OPTION},
@@ -146,6 +148,8 @@ Base%d encode or decode FILE, or standard input,
to standard output.\n\
 "), stdout);
 #if BASE_TYPE == 42
       fputs (_("\
+      --ignore-padding  base64url only: ignore missing padding at decoding,\n\
+                        don't pad at encoding\n\
       --z85             ascii85-like encoding (ZeroMQ spec:32/Z85);\n\
                         when encoding, input length must be a multiple of 4;\n\
                         when decoding, input length must be a multiple of 5\n\
@@ -335,7 +339,6 @@ base64url_decode_ctx_init_wrapper (struct
base_decode_context *ctx)
   init_inbuf (ctx);
 }

-
 static bool
 base64url_decode_ctx_wrapper (struct base_decode_context *ctx,
                               char const *restrict in, idx_t inlen,
@@ -368,7 +371,16 @@ base64url_decode_ctx_wrapper (struct
base_decode_context *ctx,
   return b;
 }

-
+static bool
+base64url_decode_ctx_wrapper_no_padding (struct base_decode_context *ctx,
+                              char const *restrict in, idx_t inlen,
+                              char *restrict out, idx_t *outlen)
+{
+    bool b = base64url_decode_ctx_wrapper(ctx, in, inlen, out, outlen);
+    if (!b && inlen == 0) // inlen 0 indicates the final round, see do_decode
+        b = true;
+    return b;
+}

 static int
 base32_length_wrapper (int len)
@@ -964,7 +976,7 @@ finish_and_exit (FILE *in, char const *infile)
 }

 static _Noreturn void
-do_encode (FILE *in, char const *infile, FILE *out, idx_t wrap_column)
+do_encode (FILE *in, char const *infile, FILE *out, idx_t
wrap_column, bool without_padding)
 {
   idx_t current_column = 0;
   char *inbuf, *outbuf;
@@ -989,9 +1001,17 @@ do_encode (FILE *in, char const *infile, FILE
*out, idx_t wrap_column)
         {
           /* Process input one block at a time.  Note that ENC_BLOCKSIZE
              is sized so that no pad chars will appear in output. */
-          base_encode (inbuf, sum, outbuf, BASE_LENGTH (sum));
+          int to_write = BASE_LENGTH (sum);
+          base_encode (inbuf, sum, outbuf, to_write);
+          if (without_padding)
+          {
+            while (*(outbuf+to_write-1) == '=')
+            {
+                --to_write;
+            }
+          }

-          wrap_write (outbuf, BASE_LENGTH (sum), wrap_column,
+          wrap_write (outbuf, to_write, wrap_column,
                       &current_column, out);
         }
     }
@@ -1084,6 +1104,13 @@ main (int argc, char **argv)
   bool decode = false;
   /* True if we should ignore non-base-alphabetic characters. */
   bool ignore_garbage = false;
+
+  /* True if we should ignore padding (base64url only). */
+#if BASE_TYPE == 42
+  bool o_ignore_padding = false;
+#endif
+  bool ignore_padding = false;
+
   /* Wrap encoded data around the 76th column, by default. */
   idx_t wrap_column = 76;

@@ -1122,6 +1149,10 @@ main (int argc, char **argv)
         break;

 #if BASE_TYPE == 42
+      case IGNORE_PADDING_OPTION:
+        o_ignore_padding = true;
+        break;
+
       case BASE64_OPTION:
       case BASE64URL_OPTION:
       case BASE32_OPTION:
@@ -1155,11 +1186,12 @@ main (int argc, char **argv)
       break;

     case BASE64URL_OPTION:
+      ignore_padding = o_ignore_padding;
       base_length = base64_length_wrapper;
       isbase = isbase64url;
       base_encode = base64url_encode;
       base_decode_ctx_init = base64url_decode_ctx_init_wrapper;
-      base_decode_ctx = base64url_decode_ctx_wrapper;
+      base_decode_ctx = ignore_padding ?
base64url_decode_ctx_wrapper_no_padding :
base64url_decode_ctx_wrapper;
       break;

     case BASE32_OPTION:
@@ -1244,5 +1276,5 @@ main (int argc, char **argv)
   if (decode)
     do_decode (input_fh, infile, stdout, ignore_garbage);
   else
-    do_encode (input_fh, infile, stdout, wrap_column);
+    do_encode (input_fh, infile, stdout, wrap_column, ignore_padding);
 }
diff --git a/tests/local.mk b/tests/local.mk
index 0496c2873..e3d9d85e2 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -728,6 +728,7 @@ all_tests = \
   tests/touch/read-only.sh \
   tests/touch/relative.sh \
   tests/touch/trailing-slash.sh \
+  tests/misc/basenc-padding.sh \
   $(all_root_tests)

 # See tests/factor/create-test.sh.
diff --git a/tests/misc/basenc-padding.sh b/tests/misc/basenc-padding.sh
new file mode 100755
index 000000000..c90f22fa1
--- /dev/null
+++ b/tests/misc/basenc-padding.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+# make sure base64url works fine without paddings
+
+# Copyright (C) 2000-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+
+
+
+input='xs?>>>x'
+
+# should be fine with wrapped writes
+b64url_encoded_wo_p="$(echo "$input" | basenc --base64url --ignore-padding)"
+
+if grep -q "=" <<< "$b64url_encoded_wo_p"; then
+    echo "Paddings are not supposed to be present"
+    Exit 1
+fi
+
+
+# note the 2>&1's, stderr should be clean
+output="$(echo "$b64url_encoded_wo_p" | basenc --base64url -d
--ignore-padding 2>&1)"
+
+if [ "$input" != "$output" ]; then
+    echo "Something is wrong without paddings (wrapped writes)"
+    Exit 1
+fi
+
+# decoding without --ignore-padding
+output_err="$(echo "$b64url_encoded_wo_p" | basenc --base64url -d 2>&1)"
+if ! grep -q "invalid input" <<< "$output_err"; then
+    echo "Decoding without --ignore-padding should still complain"
+    Exit 1
+fi
+
+# decoding errors anywhere but the last round should still complain,
even with --ignore-padding
+known_broken="eHM_Pj4*eAo"
+output="$(echo "$b64url_encoded_wo_p" | basenc --base64url -d
--ignore-padding 2>&1)"
+if ! grep -q "invalid input" <<< "$output_err"; then
+    echo "Invalid encoding anywhere but the last round should still
be rejected"
+    Exit 1
+fi
+
+# should be fine without wrapped writes
+b64url_encoded_wo_p="$(echo "$input" | basenc --base64url
--ignore-padding -w0)"
+
+# note the 2>&1's, stderr should be clean
+output="$(echo "$b64url_encoded_wo_p" | basenc --base64url -d
--ignore-padding 2>&1)"
+
+if [ "$input" != "$output" ]; then
+    echo "Something is wrong without paddings (non-wrapped writes)"
+    Exit 1
+fi
+
+# should be ok with padding as well
+b64url_encoded_w_p="$(echo "$input"| basenc --base64url)"
+
+# note the 2>&1's, stderr should be clean
+output="$(echo "$b64url_encoded_w_p" | basenc --base64url -d 2>&1)"
+
+if [ "$input" != "$output" ]; then
+    echo "Something is wrong with paddings"
+    Exit 1
+fi
+
+if [ "$b64url_encoded_w_p" == "b64url_encoded_wo_p" ]; then
+   echo "Encoding with and without padding should look different"
+   Exit 1
+fi
+
+#echo Padding test success
+
+Exit 0
-- 
2.30.2



reply via email to

[Prev in Thread] Current Thread [Next in Thread]