Sign & Encrypt vs. Encrypt & Sign – What does GPG do

digital-signatureencryptionpgp

I’ve already read the discussion Should we sign-then-encrypt, or encrypt-then-sign? and the paper Defective Sign & Encrypt in S/MIME,
PKCS#7, MOSS, PEM, PGP, and XML
. My question has to do with what gpg is doing. This has been a bit difficult to discern empirically, since the output of:

gpg --encrypt --sign <filename>

Changes each time I run it. (Why?)

@Jens has explained that part of the reason is that a timestamp is included. Is there any way to eliminate that? I’m not seeing a gpg option.

As the order of options presumably makes no difference, and since I can’t use the --detach-sign option (only a single file of output is produced, regardless), I am suspecting that the output represents:

\begin{equation}
E_r (msg\  \| \ E_s (\#msg))
\end{equation}

where $E_r$ is encryption with the recipient’s public key, $E_s$ is encryption with the sender's private key, $msg$ is the message, $\#msg$ is the hash of the message and $\|$ is concatenation. ie. this would be “sign-the-message-then-encrypt.” Is this correct?

Or is it instead:

\begin{equation}
E_r (msg) \  \| \ E_s (\#msg)
\end{equation}

In other words, is it “encrypt-then-sign-using-the-plain-text?” I am assuming it is not “encrypt-then-sign-the-cyphertext” ($E_r (msg) \ \| \ E_s (\# E_r (msg))$) as that would be counter to Section 1.2 in the paper mentioned above.

@Jens has explained that it is indeed “sign-the-message-then-encrypt.” So how would we “encrypt-then-sign-using-the-plain-text,” with the output a single openpgp file, rather than two files, one the encrypted data and the other the signature?

Also, I’ve read the papers & I’ve read the manuals – where, other than the code itself, would I go to look this up?

@Jens suggested running:

echo 'foo' | gpg --recipient [key-id] --encrypt --sign | gpg --list-packets 

I ran it, encrypting to myself and found the output below. Could someone elucidate what it's telling us?

[...]
gpg: okay, we are the anonymous recipient.
:encrypted data packet:
    length: unknown
    mdc_method: 2
gpg: encrypted with RSA key, ID 00000000
:compressed packet: algo=2
:onepass_sig packet: keyid C6701618143AFA1E
    version 3, sigclass 0x00, digest 10, pubkey 1, last=1
:literal data packet:
    mode b (62), created 1443494042, name="",
    raw data: 4 bytes
:signature packet: algo 1, keyid C6701618143AFA1E
    version 4, created 1443494042, md5len 0, sigclass 0x00
    digest algo 10, begin of digest d7 3a
    hashed subpkt 2 len 4 (sig created 2015-09-29)
    subpkt 16 len 8 (issuer key ID C6701618143AFA1E)
    data: [4095 bits]

Best Answer

This has been a bit difficult to discern empirically, since the output of:

gpg --encrypt --sign <filename>

changes each time I run it. (Why?)

This has two reasons:

  1. The symmetric encryption in OpenPGP makes use of a random initialization vector (or rather, a similar construct with a fixed initialization vector)
  2. The signature creation timestamp is included.

Sign & Encrypt vs. Encrypt & Sign - What does gpg do?

GnuPG first signs a message, then encrypts it. You can verify this using gpg --list-packets:

echo 'foo' | gpg --recipient [key-id] --encrypt --sign | gpg --list-packets

Which first signs and then encrypts a message, as the order of the packets indicates.

From my understanding of RFC 4880, OpenPGP, both orders are defined, though: OpenPGP messages can be signatures, encrypted, compressed and literal data, while signatures are applied on OpenPGP messages, and decrypted messages must also form OpenPGP messages.

Related Question