mirror of
https://codeberg.org/openpgp/notes.git
synced 2024-11-19 22:32:04 +01:00
193 lines
12 KiB
Markdown
193 lines
12 KiB
Markdown
|
<!--
|
||
|
SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project
|
||
|
SPDX-License-Identifier: CC-BY-SA-4.0
|
||
|
-->
|
||
|
|
||
|
# Zooming in: Packet structure of private key material
|
||
|
|
||
|
## A look at Alice's (unencrypted) private key packets
|
||
|
|
||
|
Let's take a look at the key material packets of [Alice's key](alice-priv).
|
||
|
|
||
|
To inspect the internal structure of Alice's key, we run the Sequoia-PGP tool `sq` (using the `packet dump` subcommand). The output of `sq` is one big block of text. To discuss the relevant content, we'll only show the output for the packets that contain key data, here:
|
||
|
|
||
|
```text
|
||
|
$ sq packet dump --hex alice.priv
|
||
|
```
|
||
|
|
||
|
### Primary Secret-Key packet
|
||
|
|
||
|
The output starts with the (primary) [Secret-Key packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-packet-formats).
|
||
|
|
||
|
This is the structure of the Secret-Key packet we will now look at.
|
||
|
|
||
|
```{figure} ../plain_svg/secret-key_packet.svg
|
||
|
:name: fig-secret-key-packet
|
||
|
:alt: Depicts a box with white background and title "Secret-Key packet". In the center a box with white background and red frame is shown. Inside it several items are listed, separated by red dotted horizontal lines. The first three are "Version", "Creation Time", "Public-Key Algorithm" written in black. The fourth one is written in green and reads "Public Key Material" and has the green public key symbol at its right side. The fifth one is again written in black and reads "S2K Usage (Secret Key Encryption)". The sixth item reads "Secret Key Material", written in red and has the red private key symbol at its right side.
|
||
|
|
||
|
Structure of a Secret-Key packet.
|
||
|
```
|
||
|
|
||
|
The output of Sequoia's `sq packet dump` for this packet:
|
||
|
|
||
|
```text
|
||
|
Secret-Key Packet, new CTB, 2 header bytes + 75 bytes
|
||
|
Version: 6
|
||
|
Creation time: 2023-09-29 15:17:58 UTC
|
||
|
Pk algo: Ed25519
|
||
|
Pk size: 256 bits
|
||
|
Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3
|
||
|
KeyID: AAA18CBB254685C5
|
||
|
|
||
|
Secret Key:
|
||
|
|
||
|
Unencrypted
|
||
|
|
||
|
00000000 c5 CTB
|
||
|
00000001 4b length
|
||
|
00000002 06 version
|
||
|
00000003 65 16 ea a6 creation_time
|
||
|
00000007 1b pk_algo
|
||
|
00000008 00 00 00 20 public_len
|
||
|
0000000c 53 24 e9 43 ed25519_public
|
||
|
00000010 af ab 15 f7 6e d5 b5 12 98 79 69 cd 1b 5d 10 65
|
||
|
00000020 eb e7 42 e2 ab 47 f4 86 b3 ae 65 3e
|
||
|
0000002c 00 s2k_usage
|
||
|
0000002d ef e1 99 ed25519_secret
|
||
|
00000030 b5 5f 11 fb aa 93 e8 26 9d 3b b2 2d 72 20 7d ff
|
||
|
00000040 bd 42 dd 4b e9 a3 36 81 3b a5 cc cf fb
|
||
|
```
|
||
|
|
||
|
The Secret-Key packet consists in large part of the actual cryptographic key data. Notice that its content is almost entirely the same as the Public-Key packet [seen in the previous chapter](zoom-public-key). Let's look at the packet field by field:
|
||
|
|
||
|
- `CTB: 0xc5`[^CTB]: The [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-headers) for this packet. The binary representation of the value `0xc5` is `11000101`. Bits 7 and 6 show that the packet is in *OpenPGP packet format* (as opposed to in *Legacy packet format*). The remaining 6 bits encode the type ID's value: "5". This is the value for a Secret-Key packet, as shown in the list of [packet type IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-types).
|
||
|
- `length: 0x4b`: The remaining length of this packet.
|
||
|
|
||
|
[^CTB]: Sequoia uses the term CTB ({term}`Cipher Type Byte`) to refer to the [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-headers).
|
||
|
|
||
|
The packet type id defines the semantics of the remaining data in the packet. We're looking at a Secret-Key packet, which is a kind of [Key Material Packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-material-packets).
|
||
|
|
||
|
- `version: 0x06`: The key material is in version 6 format
|
||
|
|
||
|
This means that the next part of the packet follows the structure of [Version 6 Public Keys](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-version-6-public-keys)
|
||
|
|
||
|
- `creation_time: 0x6516eaa6`: "The time that the key was created" (also see [Time Fields](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-time-fields))
|
||
|
- `pk_algo: 0x1b`: "The public-key algorithm ID of this key" (decimal value 27, see the list of [Public-Key Algorithms](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-public-key-algorithms))
|
||
|
- `public_len: 0x00000020`: "Octet count for the following public key material" (in this case, the length of the following `ed25519_public` field)
|
||
|
- `ed25519_public`: [Algorithm-specific representation](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-part-for-ed2) of the public key material (the format is based on the value of `pk_algo`), in this case 32 bytes of Ed25519 public key
|
||
|
|
||
|
This concludes the Public Key section of the packet. The remaining data follows the [Secret-Key packet format](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-packet-formats):
|
||
|
|
||
|
- `s2k_usage: 0x00`: The [*S2K usage* value](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-encryption-s2k-u) of `0x00` specifies that the secret-key data is not encrypted
|
||
|
- `ed25519_secret`: [Algorithm-specific representation](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-part-for-ed2) of the secret key data (the format is based on the value of `pk_algo`). Because the private key material in this packet is not encrypted, this field
|
||
|
|
||
|
```{tip}
|
||
|
|
||
|
The overall structure of OpenPGP packets is described in the [Packet Syntax](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-syntax) chapter of the RFC.
|
||
|
```
|
||
|
|
||
|
Note that the *Secret-Key packet* contains both the private and the public part of the key.
|
||
|
|
||
|
### Secret-Subkey packet
|
||
|
|
||
|
Further down in the "packet dump" of Alice's key, we see the encryption subkey, which we already inspected in its Public-Subkey packet format, [above](zoom-subkey-enc):
|
||
|
|
||
|
```text
|
||
|
Secret-Subkey Packet, new CTB, 2 header bytes + 75 bytes
|
||
|
Version: 6
|
||
|
Creation time: 2023-09-29 15:17:58 UTC
|
||
|
Pk algo: X25519
|
||
|
Pk size: 256 bits
|
||
|
Fingerprint: C0A58384A438E5A14F73712426A4D45DBAEEF4A39E6B30B09D5513F978ACCA94
|
||
|
KeyID: C0A58384A438E5A1
|
||
|
|
||
|
Secret Key:
|
||
|
|
||
|
Unencrypted
|
||
|
|
||
|
00000000 c7 CTB
|
||
|
00000001 4b length
|
||
|
00000002 06 version
|
||
|
00000003 65 16 ea a6 creation_time
|
||
|
00000007 19 pk_algo
|
||
|
00000008 00 00 00 20 public_len
|
||
|
0000000c d1 ae 87 d7 x25519_public
|
||
|
00000010 cc 42 af 99 34 c5 c2 5c ca fa b7 4a c8 43 fc 86
|
||
|
00000020 35 2a 46 01 f3 cc 00 f5 4a 09 3e 3f
|
||
|
0000002c 00 s2k_usage
|
||
|
0000002d 28 7d cd x25519_secret
|
||
|
00000030 da 26 16 37 8d ea 24 c7 ce e7 70 c7 9b e5 6f 0a
|
||
|
00000040 c9 77 fb bd 23 41 73 c9 57 5a bf 7c 4c
|
||
|
```
|
||
|
|
||
|
Again, this packet consists of the same content as its Public-Subkey equivalent, followed by two additional fields:
|
||
|
|
||
|
- The "S2K usage" field, which indicated whether the private key material is encrypted. Like Alice's primary key (above), this subkey is not encrypted.
|
||
|
- The private key material: in this case, the algorithm-specific private key data consists of 32 bytes of `x25519_secret` data.
|
||
|
|
||
|
As with the public key material, the difference between the format of this subkey packet and the private key packet is minimal: Only the packet type ID differs.
|
||
|
|
||
|
## Bob's (encrypted) private key material
|
||
|
|
||
|
Now we look at the primary key material packet of [Bob's key](bob-priv), which uses passphrase protection.
|
||
|
|
||
|
```text
|
||
|
Secret-Key Packet, new CTB, 2 header bytes + 134 bytes
|
||
|
Version: 6
|
||
|
Creation time: 2023-10-13 14:29:00 UTC
|
||
|
Pk algo: Ed25519
|
||
|
Pk size: 256 bits
|
||
|
Fingerprint: BB289FB7A68DBFA8C384CCCDE2058E02D9C6CD2F3C7C56AE7FB53D971170BA83
|
||
|
KeyID: BB289FB7A68DBFA8
|
||
|
|
||
|
Secret Key:
|
||
|
|
||
|
Encrypted
|
||
|
S2K: Argon2id with t: 1, p: 4, m: 2^21, salt: 3B7F4B0EAC8B39625AB4D4BD690413C7 Sym. algo: AES-256
|
||
|
|
||
|
00000000 c5 CTB
|
||
|
00000001 86 length
|
||
|
00000002 06 version
|
||
|
00000003 65 29 54 2c creation_time
|
||
|
00000007 1b pk_algo
|
||
|
00000008 00 00 00 20 public_len
|
||
|
0000000c 47 e7 c2 dc ed25519_public
|
||
|
00000010 58 8e cb fd f2 49 90 66 ae aa 36 66 ca a9 55 2d
|
||
|
00000020 71 88 7c 25 91 c3 75 73 1d 07 60 d6
|
||
|
0000002c fe s2k_usage
|
||
|
0000002d 16 parameters_len
|
||
|
0000002e 09 sym_algo
|
||
|
0000002f 14 s2k_len
|
||
|
00000030 04 s2k_type
|
||
|
00000031 3b 7f 4b 0e ac 8b 39 62 5a b4 d4 bd 69 04 13 argon2_salt
|
||
|
00000040 c7
|
||
|
00000041 01 argon2_t
|
||
|
00000042 04 argon2_p
|
||
|
00000043 15 argon2_m
|
||
|
00000044 21 ff be fc f1 c5 9c 75 9d 1f d1 f8 encrypted_mpis
|
||
|
00000050 19 e7 fd 47 55 e3 69 ff 2f e8 52 48 66 03 d3 37
|
||
|
00000060 52 7b 05 cb fa b1 f8 13 f7 f6 20 88 d6 f5 8b c4
|
||
|
00000070 b4 51 52 ba 6d f9 7c 1a ee 9f e6 b1 fb 63 d1 ca
|
||
|
00000080 4a 3f 33 d9 2c c9 26 46
|
||
|
```
|
||
|
|
||
|
The first portion of Bob's Secret-Key packet has the same structure as Alice's, but beginning at the `s2k_usage`, we see different data. The format of this data is described in [Secret-Key Packet Formats](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-packet-formats).
|
||
|
|
||
|
- `s2k_usage: 0xfe`: [S2K usage](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-encryption-s2k-u) is set to `AEAD`, here (decimal value 253).
|
||
|
- `parameters_len: 0x16` (decimal value: 22): "Cumulative length of all the following conditionally included string-to-key parameter fields."
|
||
|
- `sym_algo: 0x9`: [Symmetric-Key Algorithm](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-symmetric-key-algorithms) specifies that AES 256 is used as the AEAD algorithm
|
||
|
- `s2k_len: 0x14` (decimal value 20): "[..] count of the size of the one field following this octet"
|
||
|
|
||
|
The next set of data is the "string-to-key (S2K) specifier." Its format depends on the type.
|
||
|
|
||
|
- `s2k_type: 0x04` [String-to-Key (S2K) Specifier Type](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-string-to-key-s2k-specifier-), set to *Argon2* here.
|
||
|
|
||
|
The next fields are [specific to Argon2](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-argon2):
|
||
|
|
||
|
- `argon2_salt`: "16-octet salt value"
|
||
|
- `argon2_t`: "number of passes t"
|
||
|
- `argon2_p`: "degree of parallelism p"
|
||
|
- `argon2_m`: "the exponent of the memory size"
|
||
|
|
||
|
"Plain or encrypted multiprecision integers comprising the secret key data. This is algorithm-specific and described in Section 5.5.5. If the string-to-key usage octet is 253 (AEAD), then an AEAD authentication tag is at the end of that data."
|