15

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

shwoseph
  • 315
  • 1
  • 2
  • 7

3 Answers3

24

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.

schrodingerscatcuriosity
  • 12,087
  • 3
  • 29
  • 57
  • Thanks! I really wish that error message had been a little more helpful. – shwoseph Jan 28 '21 at 18:35
  • 16
    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 Jan 28 '21 at 19:21
  • 3
    ```echo -n '{"foo":"bar","baz":"bat"}' | base64 eyJmb28iOiJiYXIiLCJiYXoiOiJiYXQifQ==``` – Grump Feb 01 '21 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. – Big McLargeHuge Feb 24 '22 at 15:44
13

The command-line tool is picky about the presence of padding characters. 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"}
ilkkachu
  • 133,243
  • 15
  • 236
  • 397
6

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
wisbucky
  • 3,158
  • 1
  • 30
  • 18