Class: PacketGen::Plugin::IKE::SK

Inherits:
Payload
  • Object
show all
Includes:
Crypto
Defined in:
lib/packetgen/plugin/ike/sk.rb

Overview

This class handles encrypted payloads, denoted SK.

The encrypted payload contains other payloads in encrypted form. The Encrypted payload consists of the IKE generic payload Plugin followed by individual fields as follows:

                     1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Next Payload  |C|  RESERVED   |         Payload Length        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Initialization Vector                     |
|         (length is block size for encryption algorithm)       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~                    Encrypted IKE Payloads                     ~
+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|               |             Padding (0-255 octets)            |
+-+-+-+-+-+-+-+-+                               +-+-+-+-+-+-+-+-+
|                                               |  Pad Length   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~                    Integrity Checksum Data                    ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Encrypted payloads are set in Payload#content field, as a BinStruct::String. All others fields are only set when decrypting a previously read SK payload. They also may be set manually to encrypt IKE payloads.

Read and decrypt a SK payload

# Read a IKE packet
pkt = PacketGen.read(str)
# decrypt SK payload
cipher = OpenSSL::Cipher.new('aes-128-ctr')
cipher.decrypt
cipher_key = aes_key
hmac = OpenSSL::HMAC.new(hmac_key, OpenSSL::Digest::SHA256.new)
pkt.ike_sk.decrypt! cipher, intmode: hmac, icv_length: 16   # => true if authentication is verified
pkt.ike_sk.body       # => kind of PacketGen::Plugin::IKE::Payload

Set and encrypt a SK payload

# Create a IKE packet
pkt = PacketGen.gen('IP').add('IP').add('UDP').add('IKE', init_spi: 0x123456789, resp_spi: 0x987654321, type: 'IKE_AUTH', message_id: 1)
# Add SK payload
pkt.add('IKE::SK', icv_length: 16)
# Add others unencrypted payloads
pkt.add('IKE::IDi').add('IKE::Auth').add('IKE::SA').add('IKE::TSi').add('IKE::TSr')
# encrypt SK payload
cipher = OpenSSL::Cipher.new('aes-128-ctr')
cipher.encrypt
cipher_key = aes_key
hmac = OpenSSL::HMAC.new(hmac_key, OpenSSL::Digest::SHA256.new)
pkt.ike_sk.encrypt! cipher, iv, salt: salt, intmode: hmac
pkt.ike_sk.body       # => String
pkt.calc_length

Author:

  • Sylvain Daubert

Constant Summary collapse

PAYLOAD_TYPE =

Payload type number

46

Instance Attribute Summary collapse

Attributes inherited from Payload

#content, #critical, #flags, #hreserved, #length, #next

Instance Method Summary collapse

Methods included from Crypto

#authenticate!, #authenticated?, #compute_iv_for_decrypting, #compute_iv_for_encrypting, #confidentiality_mode, #decipher, #encipher, #set_crypto

Methods inherited from Payload

#calc_length, protocol_name

Constructor Details

#initialize(options = {}) ⇒ SK

Returns a new instance of SK.

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :icv_length (Integer)

    ICV length



76
77
78
79
# File 'lib/packetgen/plugin/ike/sk.rb', line 76

def initialize(options={})
  @icv_length = options[:icv_length] || 0
  super
end

Instance Attribute Details

#icv_lengthInteger

ICV (Integrity Check Value) length

Returns:

  • (Integer)


72
73
74
# File 'lib/packetgen/plugin/ike/sk.rb', line 72

def icv_length
  @icv_length
end

Instance Method Details

#decrypt!(cipher, options = {}) ⇒ Boolean

Decrypt in-place SK payload.

Parameters:

  • cipher (OpenSSL::Cipher)

    keyed cipher This cipher is confidentiality-only one, or AEAD one. To use a second cipher to add integrity, use :intmode option.

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :parse (Boolean)

    parse deciphered payload to retrieve Plugins (default: true)

  • :icv_length (Fixnum)

    ICV length for captured packets, or read from PCapNG files

  • :salt (String)

    salt value for CTR and GCM modes

  • :intmode (OpenSSL::HMAC)

    integrity mode to use with a confidentiality-only cipher. Only HMAC are supported.

Returns:

  • (Boolean)

    true if SK payload is authenticated



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/packetgen/plugin/ike/sk.rb', line 94

def decrypt!(cipher, options={})
  opt = { salt: '', parse: true }.merge!(options)

  set_crypto cipher, opt[:intmode]
  iv = compute_iv_for_decrypting(opt[:salt].b, self[:content])

  if authenticated?
    if @icv_length.zero?
      @icv_length = opt[:icv_length].to_i if opt[:icv_length]
      raise PacketGen::ParseError, 'unknown ICV size' if @icv_length.zero?
    end
    icv = self[:content].slice!(-@icv_length, @icv_length)
  end

  authenticate_if_needed iv, icv
  private_decrypt opt
end

#encrypt!(cipher, iv, options = {}) ⇒ self

Encrypt in-place SK payload.

Parameters:

  • cipher (OpenSSL::Cipher)

    keyed cipher This cipher is confidentiality-only one, or AEAD one. To use a second cipher to add integrity, use :intmode option.

  • iv (String)

    IV to encipher SK payload content

    • CTR and GCM modes: iv is 8-bytes long.

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :icv_length (Fixnum)

    ICV length for captured packets, or read from PCapNG files

  • :salt (String)

    salt value for CTR and GCM modes

  • :pad_length (Fixnum)

    set a padding length

  • :padding (String)

    set a padding. No check with :pad_length is made. If :pad_length is not set, :padding length is shortened to correct padding length

  • :intmode (OpenSSL::HMAC)

    integrity mode to use with a confidentiality-only cipher. Only HMAC are supported.

Returns:

  • (self)


129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/packetgen/plugin/ike/sk.rb', line 129

def encrypt!(cipher, iv, options={}) # rubocop:disable Naming/MethodParameterName
  opt = { salt: '' }.merge!(options)

  set_crypto cipher, opt[:intmode]
  compute_iv_for_encrypting iv, opt[:salt]

  authenticate_if_needed iv
  encrypted_msg = encrypt_body(iv, opt)
  encrypted_msg << generate_auth_tag(opt) if authenticated?
  self[:content].read(iv + encrypted_msg)

  # Remove plain payloads
  self[:body] = BinStruct::String.new

  remove_enciphered_packets
  self.calc_length
  self
end