Module: Rex::Proto::Kerberos::Crypto::GssNewEncryptionType

Included in:
AesBlockCipherBase
Defined in:
lib/rex/proto/kerberos/crypto/gss_new_encryption_type.rb

Overview

The RFC4121 implementation of GSS wrapping (Section 4.2.6.2) which applies to “newer encryption types” (defined as those not in section 1 of RFC4121) This mixin may be included by Encryption providers in Rex::Proto::Kerberos::Crypto

Constant Summary collapse

GSS_SENT_BY_ACCEPTOR =
1
GSS_SEALED =
2
GSS_ACCEPTOR_SUBKEY =
4
GSS_HEADER_LEN =

The length of the GSS header

16
TOK_ID_GSS_WRAP =
0x0504

Instance Method Summary collapse

Instance Method Details

#calculate_encrypted_length(plaintext_len) ⇒ Object

[View source]

91
92
93
# File 'lib/rex/proto/kerberos/crypto/gss_new_encryption_type.rb', line 91

def calculate_encrypted_length(plaintext_len)
  plaintext_len
end

#gss_unwrap(ciphertext, key, expected_sequence_number, is_initiator, opts = {}) ⇒ Object

Parameters:

  • options (Hash)

    a customizable set of options

Raises:

[View source]

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/rex/proto/kerberos/crypto/gss_new_encryption_type.rb', line 59

def gss_unwrap(ciphertext, key, expected_sequence_number, is_initiator, opts={})
  use_acceptor_subkey = opts.fetch(:use_acceptor_subkey) { true }
  # Handle wrap-around
  sequence_number &= 0xFFFFFFFFFFFFFFFF

  expected_flags = GSS_SEALED
  expected_flags |= GSS_ACCEPTOR_SUBKEY if use_acceptor_subkey

  if is_initiator
    key_usage = Rex::Proto::Kerberos::Crypto::KeyUsage::GSS_ACCEPTOR_SEAL
    expected_flags |= GSS_SENT_BY_ACCEPTOR
  else
    key_usage = Rex::Proto::Kerberos::Crypto::KeyUsage::GSS_INITIATOR_SEAL
  end
  header = ciphertext[0,GSS_HEADER_LEN]
  ciphertext = ciphertext[GSS_HEADER_LEN, ciphertext.length]

  tok_id, flags, filler, ec, rrc, snd_seq = header.unpack('nCCnnQ>')
  raise Rex::Proto::Kerberos::Model::Error::KerberosError, 'Invalid token ID' unless tok_id == TOK_ID_GSS_WRAP
  raise Rex::Proto::Kerberos::Model::Error::KerberosError, 'Invalid filler' unless filler == 0xFF
  raise Rex::Proto::Kerberos::Model::Error::KerberosError, 'Unexpected flags' unless flags == expected_flags
  raise Rex::Proto::Kerberos::Model::Error::KerberosError, "Invalid sequence number (received #{snd_seq}; expected #{expected_sequence_number})" unless expected_sequence_number == snd_seq

  # Could do some sanity checking here of those values
  ciphertext = rotate(ciphertext, -(rrc+ec))

  plaintext = self.decrypt(ciphertext, key.value, key_usage)

  plaintext = plaintext[0, plaintext.length - ec - GSS_HEADER_LEN]
  plaintext
end

#gss_wrap(plaintext, key, sequence_number, is_initiator, opts = {}) ⇒ String, Integer

Encrypt the message, wrapping it in GSS structures

Parameters:

  • options (Hash)

    a customizable set of options

Returns:

  • (String, Integer, Integer)

    The encrypted data, the length of its header, and the length of padding added to it prior to encryption

[View source]

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rex/proto/kerberos/crypto/gss_new_encryption_type.rb', line 24

def gss_wrap(plaintext, key, sequence_number, is_initiator, opts={})
  use_acceptor_subkey = opts.fetch(:use_acceptor_subkey) { true }
  # Handle wrap-around
  sequence_number &= 0xFFFFFFFFFFFFFFFF

  flags = GSS_SEALED
  flags |= GSS_ACCEPTOR_SUBKEY if use_acceptor_subkey

  if is_initiator
    key_usage = Rex::Proto::Kerberos::Crypto::KeyUsage::GSS_INITIATOR_SEAL
  else
    key_usage = Rex::Proto::Kerberos::Crypto::KeyUsage::GSS_ACCEPTOR_SEAL
    flags |= GSS_SENT_BY_ACCEPTOR
  end

  tok_id = TOK_ID_GSS_WRAP
  filler = 0xFF
  ec = calculate_ec(plaintext.length)
  rrc = calculate_rrc

  # RFC4121, Section 4.2.4
  plaintext_header = [tok_id, flags, filler, 0, 0, sequence_number].pack('nCCnnQ>')

  header = [tok_id, flags, filler, ec, rrc, sequence_number].pack('nCCnnQ>')
  # "x" chosen as the filler based on the Linux implementation of the kerberos client
  # https://salsa.debian.org/debian/krb5/-/blob/0269810b1aec6c554fb746433f045d59fd34ab3a/src/lib/gssapi/krb5/k5sealv3.c#L160
  ec_filler = "x" * ec
  plaintext = plaintext + ec_filler + plaintext_header
  ciphertext = self.encrypt(plaintext, key.value, key_usage)
  rotated = rotate(ciphertext, rrc+ec)

  result = [header + rotated, header_length + ec, ec]
end