Page MenuHome GnuPG

decrypting data symmetrically doesn't reliably convey confidentiality property
Closed, InvalidPublic

Description

Typically, symmetric encryption will in a way authenticate the decrypted data: If data can be decrypted with a given passphrase, it must also have been encrypted with that passphrase. (derp. addendum: not true in the general case if oracle attacks are relevant, and mdc only provides integrity!!)

The flexible way in which GnuPG's cli interface works makes relying on properties unreliable: A call to gpg --decrypt might unexpectedly asymmetrically decrypt, or worse, ask for a passphrase for which decryption fails, and then output a bare literal data packet that comes next in the stream. There are probably other scenarios, but more generally the nested way in which data is handled makes it difficult to reason about this one way or another.

Event Timeline

werner added a subscriber: werner.

OpenPGP does not authenticate encrypted data. To authenticate data a signature is required.
The MDC feature is what its name says - it detects modifications of the encrypted data but that's all.

Well, yes, it's not general authentication like AE provides, didn't think this through entirely. However, handing encrypted data to gnupg and then not being sure if it was actually decrypted with a passphrase makes even the confidentiality property questionable.

Valodim renamed this task from decrypting data symmetrically doesn't preserve authentication property to decrypting data symmetrically doesn't reliably convey confidentiality property.Jul 13 2017, 7:15 PM
Valodim updated the task description. (Show Details)
dkg added a subscriber: dkg.

I'm re-opening this ticket because i think Valodim has clarified what he meant, which is different than what werner closed the ticket for.

The point is the following situation:

  • i pass a chunk of data that i think was symmetrically-encrypted with passphrase X to gpg --decrypt, and
  • i also supply gpg with passphrase X (e.g. --passphrase-fd --pinentry-mode loopback), and
  • gpg gives me cleartext data back

Now i want to know the answer to the following question: was the chunk of data actually symmetrically encrypted with that passphrase, or not? It would be convenient in some situations to know the answer to this. (e.g. where no public key is available for the person you're communicating with, but you do already have some channel upon which you can already establish a shared secret to be used for the passphrase)

Can you provide samples that highlight the problem?

justus added a project: gnupg (gpg22).

I would consider this feature request. Right now you can do this by providing an empty keyring.

@justus asked for examples.

You have a contact with whom you have a low-bandwidth secure channel. Over that channel, they tell you a high-entropy secret, and say they're going to send you a file (via an insecure channel) that is symmetrically-encrypted with that secret.

You receive a file.

You go to decrypt it, but an adversary (who does not know the secret) has swapped it out for a literal data packet, armored and wrapped as a PGP MESSAGE.

You decrypt it using a tool that prompts you for your high-entropy secret and invokes GnuPG in the following way under the hood:

gpg --pinentry-mode=loopback --passphrase-fd=4  --decrypt

The output of that run is the cleartext of the adversary's message, and the only indication that it is not from the adversary is BEGIN_DECRYPTION and DECRYPTION_INFO on GnuPG's status-fd.

@werner suggests using an ephemeral home directory. this is an important point.

If the user doesn't take that suggestion, then the adversary can even make status-fd emit a BEGIN_DECRYPTION and DECRYPTION_INFO by encrypting the message to the user's encryption-capable public key.

But even if the user takes that suggestion, it is likely to be surprising that the stated invocation of gpg can return data whose confidentiality wasn't at all protected by the offered symmetric passphrase.

Here are two examples:

0 dkg@alice:/tmp/cdtemp.GIVDzD$ head -v real fake
==> real <==
-----BEGIN PGP MESSAGE-----

jA0ECQMCe7/XzOK/NEH/0kcBk3Cg1YI9Js3ZbBqB1Lm4Z4E2ViIE5ftrzIOMC8dP
aCbMIgJ3dA7ExrQ85t5m9nnkwNNzoMZLthgiyRx88GQ4ihzaNCNe0A==
=1+9Z
-----END PGP MESSAGE-----

==> fake <==
-----BEGIN PGP MESSAGE-----

yBIBO81byhDFsWpaWmJ2alElFwA=
=ByGY
-----END PGP MESSAGE-----
0 dkg@alice:/tmp/cdtemp.GIVDzD$

note the difference in status-fd:

0 dkg@alice:/tmp/cdtemp.GIVDzD$ gpg --status-fd 2 --pinentry-mode=loopback --passphrase-fd=4 4<<<abc123 --decrypt < fake
[GNUPG:] PLAINTEXT 75 1510517398 
[GNUPG:] PLAINTEXT_LENGTH 7
fakery
0 dkg@alice:/tmp/cdtemp.GIVDzD$ gpg --status-fd 2 --pinentry-mode=loopback --passphrase-fd=4 4<<<abc123 --decrypt < real
gpg: AES256 encrypted data
[GNUPG:] NEED_PASSPHRASE_SYM 9 3 2
gpg: encrypted with 1 passphrase
[GNUPG:] BEGIN_DECRYPTION
[GNUPG:] DECRYPTION_COMPLIANCE_MODE 23
[GNUPG:] DECRYPTION_INFO 2 9
[GNUPG:] PLAINTEXT 62 1510516982 
[GNUPG:] PLAINTEXT_LENGTH 19
this is the secret
[GNUPG:] DECRYPTION_OKAY
[GNUPG:] GOODMDC
[GNUPG:] END_DECRYPTION
0 dkg@alice:/tmp/cdtemp.GIVDzD$

So, to protect against this attack, the client needs to do both of the following:

  • use an ephemeral home directory
  • verify that the status-fd output actually emits the expected states

The use case that @Valodim and @dkg are thinking of probably is using a setup-code that humans use to transfer from one device do another to decrypt a symmetrically encrypted setup-package, this issue is linked from:

https://autocrypt.org/level1.html#setup-message-import

Just from reading the issue I agree that it is surprising behaviour to get some plaintext back if you attempt a symmetric decryption.

Let me state it again: Using symmetric encryption for authentication is Bad Thing™.

To authenticate a message either use a MAC or a digital signature. The two keys for the MAC and the cipher may be derived from a master key.

From the autocrypt page:

The MUA should try decrypting the message with the supplied Setup Code. The Code serves both for decryption as  well as authenticating the message. [...]

That is a no-go! In this setup message a basic protocol design rule is not followed. Ferguson/Schneier "Practical Cryptography" has a lot of good design rules; I suggest to check the setup protocol against them.

@werner, what protocol design rule do you think is not being followed specifically?

Authenticated Encryption is a standard primitive in modern cryptographic systems. If common OpenPGP implementations offered an AEAD scheme, i'm sure Autocrypt would make use of it. The closest that GnuPG offers is SEIPD (which pre-dates the standardization of AEAD), and that is what Autocrypt uses.

In the Autocrypt Setup Message case, there is no choice of trusted keys, so the high-entropy autocrypt setup code acts as an authentication mechanism. It's far from ideal, of course, but it's trying to make things work with existing cryptographic toolkits (like GnuPG). If you have another suggestion for this use case, I'm sure the autocrypt project would be happy to hear about it.

To use encryption and for both purposes: encryption and authentication.

AE is a different thing because it clearly separates both purposes. In OpenPGP we do not have AE yet. The MDC has not that property.

Let me please close this bug again as such a discussion should not take place in a bug tracker.

I'm sorry but the explanation you give does not address the original issue I described, and which dkg then clarified. The discussion about AE is tangentially related, but the issue I described relates to the gpg interface:

The flexible way in which GnuPG's cli interface works makes relying on properties unreliable: A call to gpg --decrypt might unexpectedly asymmetrically decrypt, or worse, ask for a passphrase for which decryption fails, and then output a bare literal data packet that comes next in the stream.

Even if encryption happened with an AE mode, there would (I think) be no way to reliably use gpg --decrypt to specifically decrypt a given ciphertext with a given passphrase. It might be possible to achieve the same effect by using an empty keyring, and maybe bypassing the passphrase cache in the agent(?), and possibly other things that may or may not change between versions now or in the future. This requires a lot of knowledge, and conversely leads to a high chance of usage errors, for something as simple as decrypting a message with a given passphrase.

In T3464 is is described how you can do it. Sure, in your case you want to have a home directory so that the agent and pinentry can work. --no-keyring makes sure that a decryption with a private key can't happen. How we have the cache for symmetric encrypted data which you can disable with --no-symkey-cache.

Granted that is not straightforward but you try to do things for which gpg is not designed. The --verify command would be what you want as API but we do not have such symmetric key authentication feature in gpg.