OpenPGP message: format specification

The OpenPGP Message Format is a format to store encryption and signature keys for emails.

File extension

["gpg", "pub", "pgp"]

KS implementation details

License: MIT

References

This page hosts a formal specification of OpenPGP message using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Block diagram

Format specification in Kaitai Struct YAML

meta:
  id: openpgp_message
  title: OpenPGP message
  file-extension:
    - gpg
    - pub
    - pgp
  xref:
    justsolve: PGP
    rfc: 4880
    wikidata: Q2141493
  license: MIT
  encoding: UTF-8
  endian: be
doc: The OpenPGP Message Format is a format to store encryption and signature keys for emails.
doc-ref: https://www.rfc-editor.org/rfc/rfc4880
seq:
  - id: packets
    type: packet
    repeat: eos
types:
  packet:
    -webide-representation: '{packet_type_old}'
    seq:
      - id: one
        type: b1
      - id: new_packet_format
        type: b1
      - id: packet_type_new
        type: b6
        if: new_packet_format
        enum: packet_tags
      - id: packet_type_old
        type: b4
        if: not new_packet_format
        enum: packet_tags
      - id: len_type
        type: b2
        if: not new_packet_format
      - id: body
        type:
          switch-on: new_packet_format
          cases:
            #true: new_packet
            false: old_packet

  old_packet:
    seq:
      - id: len
        type:
          switch-on: _parent.len_type
          cases:
            0: u1
            1: u2
            2: u4
      - id: body
        size: len
        type:
          switch-on: _parent.packet_type_old
          cases:
            packet_tags::user_id_packet: user_id_packet
            packet_tags::signature_packet: signature_packet
            packet_tags::public_key_packet: public_key_packet
            packet_tags::public_subkey_packet: public_key_packet
            packet_tags::secret_key_packet: secret_key_packet
            packet_tags::secret_subkey_packet: public_key_packet

  public_key_packet:
    seq:
      - id: version
        type: u1
      - id: timestamp
        type: u4
      - id: public_key_algorithm
        type: u1
        enum: public_key_algorithms
      - id: len_alg
        type: u2
      - id: rsa_n
        size: len_alg / 8
      - id: padding
        type: u2
      - id: rsa_e
        size: 3

  user_id_packet:
    seq:
      - id: user_id
        size-eos: true
        type: str

  signature_packet:
    seq:
      - id: version
        type: u1
        # enum: TODO switch?
      - id: signature_type
        type: u1
        # enum: TODO 5.2.1
      - id: public_key_algorithm
        type: u1
        enum: public_key_algorithms
      - id: hash_algorithm
        type: u1
        enum: hash_algorithms
      - id: len_hashed_subpacket
        type: u2
      - id: hashed_subpackets
        type: subpackets
        size: len_hashed_subpacket
      - id: len_unhashed_subpacket
        type: u2
      - id: unhashed_subpackets
        type: subpackets
        size: len_unhashed_subpacket
      - id: left_signed_hash
        type: u2
      - id: rsa_n
        type: u2
      - id: signature
        size-eos: true

  secret_key_packet:
    seq:
      - id: public_key
        type: public_key_packet
      - id: string_to_key
        type: u1
      - id: symmetric_encryption_algorithm
        type: u1
        enum: symmetric_key_algorithm
        if: string_to_key >= 254
      - id: secret_key
        size-eos: true

  subpackets:
    seq:
      - id: subpacketss
        type: subpacket
        repeat: eos

  subpacket:
    seq:
      - id: len
        type: len_subpacket
      - id: subpacket_type
        type: u1
        enum: subpacket_types
      - id: content
        size: len.len - 1
        type:
          switch-on: subpacket_type
          cases:
            subpacket_types::signature_creation_time: signature_creation_time
            subpacket_types::issuer: issuer
            subpacket_types::key_expiration_time: key_expiration_time
            subpacket_types::preferred_hash_algorithms: preferred_hash_algorithms
            subpacket_types::preferred_compression_algorithms: preferred_compression_algorithms
            subpacket_types::signature_expiration_time: signature_expiration_time
            subpacket_types::exportable_certification: exportable_certification
            subpacket_types::revocable: revocable
            subpacket_types::trust_signature: trust_signature
            subpacket_types::regular_expression: regular_expression
            subpacket_types::revocation_key: revocation_key
            subpacket_types::notation_data: notation_data
            subpacket_types::key_server_preferences: key_server_preferences
            subpacket_types::preferred_key_server: preferred_key_server
            subpacket_types::primary_user_id: primary_user_id
            subpacket_types::policy_uri: policy_uri
            subpacket_types::key_flags: key_flags
            subpacket_types::signers_user_id: signers_user_id
            subpacket_types::reason_for_revocation: reason_for_revocation
            subpacket_types::features: features
            subpacket_types::signature_target: signature_target
            subpacket_types::embedded_signature: embedded_signature

  len_subpacket:
    -webide-representation: '{len}'
    seq:
      - id: first_octet
        type: u1
      - id: second_octet
        type: u1
        if: first_octet >= 192 and first_octet < 255
      - id: scalar
        type: u4
        if: first_octet == 255
    instances:
      len:
        value: 'first_octet < 192 ? first_octet : ((first_octet >= 192 and first_octet < 255) ? (((first_octet - 192) << 8) + second_octet + 192) : scalar)'

  signature_creation_time:
    seq:
      - id: time
        type: u4

  issuer:
    seq:
      - id: keyid
        type: u8

  key_expiration_time:
    seq:
      - id: time
        type: u4

  preferred_hash_algorithms:
    seq:
      - id: algorithm
        type: u1
        enum: hash_algorithms
        repeat: eos

  preferred_compression_algorithms:
    seq:
      - id: algorithm
        type: u1
        enum: compression_algorithms
        repeat: eos

  signature_expiration_time:
    seq:
      - id: time
        type: u4

  exportable_certification:
    seq:
      - id: exportable
        type: u1

  revocable:
    seq:
      - id: revocable
        type: u1

  trust_signature:
    seq:
      - id: level
        type: u1
      - id: amount
        type: u1

  regular_expression:
    seq:
      - id: regex
        type: strz

  revocation_key:
    seq:
      - id: class
        type: u1
      - id: public_key_algorithm
        enum: public_key_algorithms
        type: u1
      - id: fingerprint
        size: 20

  notation_data:
    seq:
      - id: flags
        size: 4
      - id: len_name
        type: u2
      - id: len_value
        type: u2
      - id: name
        size: len_name
      - id: value
        size: len_value

  key_server_preferences:
    seq:
      - id: flag
        type: u1
        enum: server_flags
        repeat: eos

  preferred_key_server:
    seq:
      - id: uri
        type: str
        size-eos: true

  primary_user_id:
    seq:
      - id: user_id
        type: u1

  policy_uri:
    seq:
      - id: uri
        type: str
        size-eos: true

  key_flags:
    seq:
      - id: flag
        type: u1
        enum: key_flags
        repeat: eos

  signers_user_id:
    seq:
      - id: user_id
        type: str
        size-eos: true

  reason_for_revocation:
    seq:
      - id: revocation_code
        type: u1
        enum: revocation_codes
      - id: reason
        type: str
        size-eos: true

  features:
    seq:
      - id: flags
        size-eos: true

  signature_target:
    seq:
      - id: public_key_algorithm
        type: u1
        enum: public_key_algorithms
      - id: hash_algorithm
        type: u1
        enum: hash_algorithms
      - id: hash
        size-eos: true

  embedded_signature:
    seq:
      - id: signature_packet
        type: signature_packet

enums:
  packet_tags:
    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: private_or_experimental_values_0
    61: private_or_experimental_values_1
    62: private_or_experimental_values_2
    63: private_or_experimental_values_3

  public_key_algorithms:
    1: rsa_encrypt_or_sign_hac
    2: rsa_encrypt_only_hac
    3: rsa_sign_only_hac
    16: elgamal_encrypt_only_elgamal_hac
    17: dsa_digital_signature_algorithm_fips_hac
    18: reserved_for_elliptic_curve
    19: reserved_for_ecdsa
    20: reserved_formerly_elgamal_encrypt_or_sign_
    21: reserved_for_diffie_hellman_x_as_defined_for_ietf_s_mime
    100: private_experimental_algorithm_00
    101: private_experimental_algorithm_01
    102: private_experimental_algorithm_02
    103: private_experimental_algorithm_03
    104: private_experimental_algorithm_04
    105: private_experimental_algorithm_05
    106: private_experimental_algorithm_06
    107: private_experimental_algorithm_07
    108: private_experimental_algorithm_08
    109: private_experimental_algorithm_09
    110: private_experimental_algorithm_10

  symmetric_key_algorithm:
    0: plain
    1: idea
    2: triple_des
    3: cast5
    4: blowfisch
    5: reserved5
    6: reserved6
    7: aes_128
    8: aes_192
    9: aes_256
    10: twofish_256
    100: private_experimental_algorithm_00
    101: private_experimental_algorithm_01
    102: private_experimental_algorithm_02
    103: private_experimental_algorithm_03
    104: private_experimental_algorithm_04
    105: private_experimental_algorithm_05
    106: private_experimental_algorithm_06
    107: private_experimental_algorithm_07
    108: private_experimental_algorithm_08
    109: private_experimental_algorithm_09
    110: private_experimental_algorithm_10

  hash_algorithms:
    1: md5
    2: sha1
    3: ripemd160
    4: reserved4
    5: reserved5
    6: reserved6
    7: reserved7
    8: sha256
    9: sha384
    10: sha512
    11: sha224
    100: private_experimental_algorithm_00
    101: private_experimental_algorithm_01
    102: private_experimental_algorithm_02
    103: private_experimental_algorithm_03
    104: private_experimental_algorithm_04
    105: private_experimental_algorithm_05
    106: private_experimental_algorithm_06
    107: private_experimental_algorithm_07
    108: private_experimental_algorithm_08
    109: private_experimental_algorithm_09
    110: private_experimental_algorithm_10

  compression_algorithms:
    0: uncompressed
    1: zib
    2: zlib
    3: bzip
    100: private_experimental_algorithm_00
    101: private_experimental_algorithm_01
    102: private_experimental_algorithm_02
    103: private_experimental_algorithm_03
    104: private_experimental_algorithm_04
    105: private_experimental_algorithm_05
    106: private_experimental_algorithm_06
    107: private_experimental_algorithm_07
    108: private_experimental_algorithm_08
    109: private_experimental_algorithm_09
    110: private_experimental_algorithm_10

  subpacket_types:
    0: reserved0
    1: reserved1
    2: signature_creation_time
    3: signature_expiration_time
    4: exportable_certification
    5: trust_signature
    6: regular_expression
    7: revocable
    8: reserved8
    9: key_expiration_time
    10: placeholder_for_backward_compatibility
    11: preferred_symmetric_algorithms
    12: revocation_key
    13: reserved13
    14: reserved14
    15: reserved15
    16: issuer
    17: reserved17
    18: reserved18
    19: reserved19
    20: notation_data
    21: preferred_hash_algorithms
    22: preferred_compression_algorithms
    23: key_server_preferences
    24: preferred_key_server
    25: primary_user_id
    26: policy_uri
    27: key_flags
    28: signers_user_id
    29: reason_for_revocation
    30: features
    31: signature_target
    32: embedded_signature

  server_flags:
    0x80: no_modify

  key_flags:
    0x01: this_key_may_be_used_to_certify_other_keys
    0x02: this_key_may_be_used_to_sign_data
    0x04: this_key_may_be_used_to_encrypt_communications
    0x08: this_key_may_be_used_to_encrypt_storage
    0x10: the_private_component_of_this_key_may_have_been_split_by_a_secret_sharing_mechanism
    0x20: this_key_may_be_used_for_authentication
    0x80: the_private_component_of_this_key_may_be_in_the_possession_of_more_than_one_person

  revocation_codes:
    0: no_reason_specified_key_revocations_or_cert_revocations
    1: key_is_superseded_key_revocations
    2: key_material_has_been_compromised_key_revocations
    3: key_is_retired_and_no_longer_used_key_revocations
    32: user_id_information_is_no_longer_valid_cert_revocations
    100: private_use_1
    101: private_use_2
    102: private_use_3
    103: private_use_4
    110: private_use_11