2
root@e8c1b013eb50:/# # let's make encryption first
root@e8c1b013eb50:/# echo -n 123 | openssl enc -aes-256-cbc -e -K 7 -iv 1 -a -p
hex string is too short, padding with zero bytes to length
hex string is too short, padding with zero bytes to length
salt=73C782D6357F0000
key=7000000000000000000000000000000000000000000000000000000000000000
iv =10000000000000000000000000000000
TUnoQ0azKuL6oto9DNDhHQ==
root@e8c1b013eb50:/#
root@e8c1b013eb50:/# # let's try to decrypt
root@e8c1b013eb50:/# echo -n "TUnoQ0azKuL6oto9DNDhHQ==" | openssl enc -aes-256-cbc -d -K 7 -iv 1 -a -p
hex string is too short, padding with zero bytes to length
hex string is too short, padding with zero bytes to length
salt=73470479277F0000
key=7000000000000000000000000000000000000000000000000000000000000000
iv =10000000000000000000000000000000
bad decrypt
139807510111552:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:../crypto/evp/evp_enc.c:599:
root@e8c1b013eb50:/#
root@e8c1b013eb50:/# # oops, let's add extra newline for input
root@e8c1b013eb50:/# echo "TUnoQ0azKuL6oto9DNDhHQ==" | openssl enc -aes-256-cbc -d -K 7 -iv 1 -a -p
hex string is too short, padding with zero bytes to length
hex string is too short, padding with zero bytes to length
salt=73E7CADCB67F0000
key=7000000000000000000000000000000000000000000000000000000000000000
iv =10000000000000000000000000000000
123root@e8c1b013eb50:/# # see, it works with extra newline
root@e8c1b013eb50:/#

Let's check it out

  1. Encrypt 123 into TUnoQ0azKuL6oto9DNDhHQ==, here I believe it is TUnoQ0azKuL6oto9DNDhHQ== rather than TUnoQ0azKuL6oto9DNDhHQ==\n, cipher data has no reason happens ending with \n, and, even if cipher data is ending with \n, here it is base64 encoded, so... Am I correct?
  2. Since the encryption result is TUnoQ0azKuL6oto9DNDhHQ==, it has to be TUnoQ0azKuL6oto9DNDhHQ== which goes to decryption process, but it failed with block length issue
  3. If we provide extra \n, then decrypt went fine

Here is the point
If we encrypt A into B
Then we should decrypt B into A
That's what we define symmetric encryption
Not something like A into B, B\n into A
So much confused, thanks in advance.

2
  • 1
    It seems that this might be just some nuance with the -a option, whereby openssl requires the base64 string to be terminated with the \n when feeding it a base64 input with this option. If you decode the base64 (without the \n terminator) first, then feed the decoded bytes to openssl, it works, e.g.: echo -n "TUnoQ0azKuL6oto9DNDhHQ==" | base64 -d | openssl enc -aes-256-cbc -d -K 7 -iv 1 -p
    – mti2935
    Commented Feb 11, 2022 at 13:08
  • appreciate it so much especially with proof attached, thank you
    – http8086
    Commented Feb 11, 2022 at 15:22

1 Answer 1

6

In short: it is somehow broken, but not the decryption, only the base64 decoding.

With -a you explicitly specify that the output should be encoded in base64. The newline expected on input for decryption is the same as the newline added to the output on encryption, only you did not consider this part of the output.

That the newline is part of the output gets more obvious when the output is not a short string but a much longer one (like 50 characters). Then you'll see as output a multi-line string:

$ echo -n 01234567890123456789012345678901234567890123456789 | openssl enc -aes-256-cbc -e -K 7 -iv 1 -a -p
hex string is too short, padding with zero bytes to length
hex string is too short, padding with zero bytes to length
salt=7307BF88947F0000
key=7000000000000000000000000000000000000000000000000000000000000000
iv =10000000000000000000000000000000
ekCT17lepPeLxr6Aoa99FfPjvcUzv2RvENAzalqW4J/XJx07PtsB9Oyysnc7CchV
X/B/Lz6C8IpeTCREZqaxqg==

It gets also more obvious if no output encoding is requested, i.e. the option -a is omitted. In this case the output is binary - with no newline added to the output.

In other words: As long as you feed the output of the encryption into the decryption it works. If you omit data which you did not consider part of the output (like the final newline) then it might stop working.

Note that you can make enc not require the newline on input, nor make it output the newline on output. Just use additionally the option -A:

-A If the -a option is set then base64 process the data on one line.

Note also that I would consider the behavior of openssl broken here. Looking at the code it looks like it expects at least one newline in the input of the base64 BIO, unless the flag BIO_FLAGS_BASE64_NO_NL is set (which is the mentioned -A). Once this newline is found it does not care about any more newlines, i.e. it is perfectly fine if there is no newline at the end of the input. To demonstrate:

$ echo -ne 'MTIz' | openssl base64 -d
<no output>
$ echo -ne 'MTIz\n' | openssl base64 -d
123
$ echo -ne 'MTIz\nMTIz' | openssl base64 -d
123123

In the first try it will fail to decode anything since no newline is found. Adding -A here would make it succeed. In the second try it succeeds to decode since the newline is found. The last try shows that it succeeds in decoding even if the input does not end with newline - as long a single newline was found in the input.

For more on this problem see this bug report

5
  • Nice answer, +1. It seems that there is something squirrelly with the way that the -a option with openssl enc seems to require the base64 encoded input to be terminated with \n. It shouldn't make a difference, as \n is not one of the characters in the base64 character set - e.g. echo "TUnoQ0azKuL6oto9DNDhHQ==" | base64 -d | xxd -p produces the same output as echo -n "TUnoQ0azKuL6oto9DNDhHQ==" | base64 -d | xxd -p
    – mti2935
    Commented Feb 11, 2022 at 13:24
  • @mti2935: yes, its broken. See updated answer. Commented Feb 11, 2022 at 16:53
  • Very interesting. Thanks for tracking this down and posting it.
    – mti2935
    Commented Feb 11, 2022 at 20:37
  • As I said on the earlier Q, OpenSSL's base64 was originally to support PEM, which requires linebreaks every 64 chars (if more) and at the end, and that's still the main purpose. 64 chars encodes 48 bytes, and for AES CBC with (by default) PKCS5/7 padding, >=48 bytes plaintext results in >48 bytes ciphertext thus more than one line. (But if you use enc's default password-based encryption with salt it adds a 16-byte header to the ciphertext.) Commented Feb 12, 2022 at 1:29
  • @dave_thompson_085: You are correct and your statements are also included in the bug report I've found. Nevertheless - the historic knowledge of this and its implications can not be be expected by someone using OpenSSL., the more so as the behavior is not even documented (at least I did not found anything). The expectation is that something claiming to implement base64 should actually implement what is commonly understood as base64. That's why I still consider it broken. Commented Feb 12, 2022 at 4:41

You must log in to answer this question.

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