What you've defined in your process is called Key Encapsulation. It's how TLS functions as well as GPG and many other cryptographic data exchange protocols.
GPG is particularly easy to demonstrate, since there is an option to list detailed information regarding what is contained within the PGP message. This option is --list-packets
, and along with a little information from the standard, RFC4880, it's fairly easy to dissect an encrypted PGP message.
Here are the applicable areas of RFC4880:
4.3. Packet Tags
The packet tag denotes what type of packet the body holds. Note that
old format headers can only have tags less than 16, whereas new
format headers can have tags as great as 63. The defined tags (in
decimal) are as follows:
0 -- Reserved - a packet tag MUST NOT have this value
1 -- Public-Key Encrypted Session Key Packet
2 -- Signature Packet
3 -- Symmetric-Key Encrypted Session Key Packet
4 -- One-Pass Signature Packet
5 -- Secret-Key Packet
6 -- Public-Key Packet
7 -- Secret-Subkey Packet
8 -- Compressed Data Packet
9 -- Symmetrically Encrypted Data Packet
10 -- Marker Packet
11 -- Literal Data Packet
12 -- Trust Packet
13 -- User ID Packet
14 -- Public-Subkey Packet
17 -- User Attribute Packet
18 -- Sym. Encrypted and Integrity Protected Data Packet
19 -- Modification Detection Code Packet
60 to 63 -- Private or Experimental Values
...
5.1. Public-Key Encrypted Session Key Packets (Tag 1)
A Public-Key Encrypted Session Key packet holds the session key used
to encrypt a message. Zero or more Public-Key Encrypted Session Key
packets and/or Symmetric-Key Encrypted Session Key packets may
precede a Symmetrically Encrypted Data Packet, which holds an
encrypted message. The message is encrypted with the session key,
and the session key is itself encrypted and stored in the Encrypted
Session Key packet(s). The Symmetrically Encrypted Data Packet is
preceded by one Public-Key Encrypted Session Key packet for each
OpenPGP key to which the message is encrypted. The recipient of the
message finds a session key that is encrypted to their public key,
decrypts the session key, and then uses the session key to decrypt
the message.
So, what we're looking for is a packet with Tag 1: Public-Key Encrypted Session Key Packet, which contains the encrypted symmetric key that was used to encrypt message.
Let's generate an Elliptic Curve25519 test key and experiment:
gpg --expert --full-gen-key
pub ed25519 2019-01-05 [SC]
8142894DE02523BAC0B830518D1D7EACEC02106D
uid [ultimate] Demo Key 2 (Delete Me) <[email protected]>
sub cv25519 2019-01-05 [E]
Here's a listing of the generated key:
gpg --list-key --keyid-format long [email protected]
pub ed25519/8D1D7EACEC02106D 2019-01-05 [SC]
8142894DE02523BAC0B830518D1D7EACEC02106D
uid [ultimate] Demo Key 2 (Delete Me) <[email protected]>
sub cv25519/7B2F2DF3D9ABA877 2019-01-05 [E]
Now create an encrypted message:
echo -e "Hello There.\n" | gpg -o message.gpg -er [email protected]
Let's look at what's in the encrypted message:
gpg --list-packets message.gpg
gpg: encrypted with 256-bit ECDH key, ID 7B2F2DF3D9ABA877, created 2019-01-05
"Demo Key 2 (Delete Me) <[email protected]>"
# off=0 ctb=84 tag=1 hlen=2 plen=94
:pubkey enc packet: version 3, algo 18, keyid 7B2F2DF3D9ABA877
data: [263 bits]
data: [392 bits]
# off=96 ctb=d2 tag=18 hlen=2 plen=73 new-ctb
:encrypted data packet:
length: 73
mdc_method: 2
# off=117 ctb=a3 tag=8 hlen=1 plen=0 indeterminate
:compressed packet: algo=2
# off=119 ctb=cb tag=11 hlen=2 plen=20 new-ctb
:literal data packet:
mode b (62), created 1546740749, name="",
raw data: 14 bytes
Yes, indeed there is a packet with Tag 1. This packet contains an encrypted symmetric session key which was used to encrypt the message.
It's useful to note that there is very little effective difference between the process of how GPG encrypts messages and how TLS functions at the cryptographic level. The protocol is a bit different and the trust anchors are different, but the mechanism used to encrypt the data and decrypt it at the far end are nearly the same. In both cases, there is a symmetric session key that is used to encrypt the message. In both cases, the symmetric message key is encrypted with the public key of the receiver and sent along with the encrypted message itself.
It's clear that your described algorithm matches what is routinely done programmatically by many modern cryptographic messaging systems.
So, yes GPG satisfies the requirement on the transmission side. However, how can you be sure that the transmitted message or file has not been replaced?
And this is where the server signatures on the file become important. Many software developers have adopted the method of generating a SHA256SUM hash of the distributed file and then signing the hash sum list with the developer private key. The signed sums are distributed via TLS enabled web pages. This completes the loop. The receiver of the file can now ensure that the received file is the same file distributed by the server by checking the downloaded file's hash against the server displayed and signed hash list.
sha256sum
of the file which can be used by the receiving server to quickly ensure that the transmitted large file+key has been received properly and without modification... a little better, have the master server PGP sign the sha256sum