Sign & Encrypt vs. Encrypt & Sign - What does GPG do?
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]
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:
- The symmetric encryption in OpenPGP makes use of a random initialization vector (or rather, a similar construct with a fixed initialization vector)
- 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.