Class: PacketGen::Plugin::IKE::SK
- 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 Types::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
Constant Summary collapse
- PAYLOAD_TYPE =
Payload type number
46
Instance Attribute Summary collapse
-
#icv_length ⇒ Integer
ICV (Integrity Check Value) length.
Attributes inherited from Payload
#content, #critical, #flags, #hreserved, #length, #next
Instance Method Summary collapse
-
#decrypt!(cipher, options = {}) ⇒ Boolean
Decrypt in-place SK payload.
-
#encrypt!(cipher, iv, options = {}) ⇒ self
Encrypt in-place SK payload.
-
#initialize(options = {}) ⇒ SK
constructor
A new instance of SK.
Methods included from Crypto
#authenticate!, #authenticated?, #confidentiality_mode, #decipher, #encipher, #set_crypto
Methods inherited from Payload
Constructor Details
#initialize(options = {}) ⇒ SK
Returns a new instance of SK.
76 77 78 79 |
# File 'lib/packetgen/plugin/ike/sk.rb', line 76 def initialize(={}) @icv_length = [:icv_length] || 0 super end |
Instance Attribute Details
#icv_length ⇒ Integer
ICV (Integrity Check Value) length
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.
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/packetgen/plugin/ike/sk.rb', line 94 def decrypt!(cipher, ={}) opt = { salt: '', parse: true }.merge!() set_crypto cipher, opt[:intmode] case confidentiality_mode when 'gcm' iv = self[:content].slice!(0, 8) real_iv = force_binary(opt[:salt]) + iv when 'cbc' cipher.padding = 0 real_iv = iv = self[:content].slice!(0, 16) when 'ctr' iv = self[:content].slice!(0, 8) real_iv = force_binary(opt[:salt]) + iv + [1].pack('N') else real_iv = iv = self[:content].slice!(0, 16) end cipher.iv = real_iv 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.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/packetgen/plugin/ike/sk.rb', line 143 def encrypt!(cipher, iv, ={}) opt = { salt: '' }.merge!() set_crypto cipher, opt[:intmode] real_iv = force_binary(opt[:salt]) + force_binary(iv) real_iv += [1].pack('N') if confidentiality_mode == 'ctr' cipher.iv = real_iv authenticate_if_needed iv if opt[:pad_length] pad_length = opt[:pad_length] padding = force_binary(opt[:padding] || ([0] * pad_length).pack('C*')) else pad_length = cipher.block_size pad_length = 16 if cipher.block_size == 1 # Some AES mode returns 1... pad_length -= (self[:body].sz + iv.size + 1) % cipher.block_size pad_length = 0 if pad_length == 16 padding = force_binary(opt[:padding] || ([0] * pad_length).pack('C*')) padding = padding[0, pad_length] end msg = self[:body].to_s + padding + PacketGen::Types::Int8.new(pad_length).to_s encrypted_msg = encipher(msg) cipher.final # message is already padded. No need for mode padding if authenticated? @icv_length = opt[:icv_length] if opt[:icv_length] encrypted_msg << if @conf.authenticated? @conf.auth_tag[0, @icv_length] else @intg.digest[0, @icv_length] end end self[:content].read(iv + encrypted_msg) # Remove plain payloads self[:body] = PacketGen::Types::String.new # Remove enciphered payloads from packet id = header_id(self) if id < packet.headers.size - 1 (packet.headers.size - 1).downto(id + 1) do |index| packet.headers.delete_at index end end self.calc_length self end |