18

Does anybody know why this is happening and how to fix it?

me@box:~$ echo "eyJmb28iOiJiYXIiLCJiYXoiOiJiYXQifQ" | base64 -di
{"foo":"bar","baz":"bat"}base64: invalid input

0

3 Answers 3

27

If you do the reverse, you'll note that the string isn't complete:

$ echo '{"foo":"bar","baz":"bat"}' | base64
eyJmb28iOiJiYXIiLCJiYXoiOiJiYXQifQo=

$ echo "eyJmb28iOiJiYXIiLCJiYXoiOiJiYXQifQo=" | base64 -di
{"foo":"bar","baz":"bat"}

Extracts of Why does base64 encoding require padding if the input length is not divisible by 3?

What are Padding Characters?

Padding characters help satisfy length requirements and carry no meaning.

However, padding is useful in situations where base64 encoded strings are concatenated in such a way that the lengths of the individual sequences are lost, as might happen, for example, in a very simple network protocol.

If unpadded strings are concatenated, it's impossible to recover the original data because information about the number of odd bytes at the end of each individual sequence is lost. However, if padded sequences are used, there's no ambiguity, and the sequence as a whole can be decoded correctly.

3
  • 17
    Note that the string you used here is slightly different than the original, as echo adds a trailing newline. The original string without it would be correctly padded as ...ifQ==. In this case, both versions do require padding though.
    – ilkkachu
    Commented Jan 28, 2021 at 19:21
  • 3
    echo -n '{"foo":"bar","baz":"bat"}' | base64 eyJmb28iOiJiYXIiLCJiYXoiOiJiYXQifQ==
    – Grump
    Commented Feb 1, 2021 at 11:23
  • Keep in mind the "input length" referred to is in bytes. If referring to the number of characters, the length should be divisible by 4. Commented Feb 24, 2022 at 15:44
16

The command-line tools are picky about the proper amount of padding characters to make the input length a multiple of four. That string is 34 characters long, so there should be two = signs as padding at the end.

$ echo "eyJmb28iOiJiYXIiLCJiYXoiOiJiYXQifQ==" | base64 -di; echo
{"foo":"bar","baz":"bat"}

With an input that's missing the padding characters, the result varies between implementations. The proper Base64 encoding of abcd is YWJjZA==:

% echo -n abcd |base64
YWJjZA==

If we try to decode that with the padding characters removed, the last part just gets silently dropped on Mac:

% echo 'YWJjZA' |base64 -d
abc

While with the GNU implementation, the full output is there, but we get an error message (to stderr):

$ echo 'YWJjZA' |base64 -d
abcdbase64: invalid input
11

GNU's base64 -d requires proper padding (input length must be a multiple of 4). Other base64 decoders may be smarter and not require padding (e.g. Mac/BSD base64 -D does not require padding).

Here's a bash command that can automatically pad the base64 string properly. Then you won't get the "invalid input" error.

str="eyJmb28iOiJiYXIiLCJiYXoiOiJiYXQifQ"

echo "$str"==== | fold -w 4 | sed '$ d' | tr -d '\n' | base64 --decode

Explanation:

  • echo "$str"==== appends 4 equal signs
  • fold -w 4 split every 4 characters into separate lines
  • sed '$ d' deletes the last line (the extraneous padding)
  • tr -d '\n' joins all lines
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .