packetgen-plugin-ipsec 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/specs.yml +7 -3
- data/.rubocop.yml +24 -6
- data/Gemfile +13 -6
- data/README.md +12 -6
- data/lib/packetgen/plugin/crypto.rb +32 -0
- data/lib/packetgen/plugin/esp.rb +162 -133
- data/lib/packetgen/plugin/ike/auth.rb +52 -39
- data/lib/packetgen/plugin/ike/cert.rb +1 -1
- data/lib/packetgen/plugin/ike/certreq.rb +1 -1
- data/lib/packetgen/plugin/ike/id.rb +7 -8
- data/lib/packetgen/plugin/ike/ke.rb +6 -5
- data/lib/packetgen/plugin/ike/nonce.rb +1 -1
- data/lib/packetgen/plugin/ike/notify.rb +12 -13
- data/lib/packetgen/plugin/ike/payload.rb +30 -32
- data/lib/packetgen/plugin/ike/sa.rb +41 -41
- data/lib/packetgen/plugin/ike/sk.rb +76 -74
- data/lib/packetgen/plugin/ike/ts.rb +20 -17
- data/lib/packetgen/plugin/ike/vendor_id.rb +1 -1
- data/lib/packetgen/plugin/ike.rb +37 -42
- data/lib/packetgen/plugin/ipsec_version.rb +1 -1
- data/lib/packetgen-plugin-ipsec.rb +2 -0
- data/packetgen-plugin-ipsec.gemspec +5 -4
- metadata +10 -18
- data/.travis.yml +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63e6c93595c3d2f6361e87c0c5dd6cf60a792fadf6f15ecd52a8fe38be56bf29
|
4
|
+
data.tar.gz: 7759ddd4bdb74e1b510db940114c38e89ac6865d803c8966ebbc2b80c7379f97
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dab304078f641492b8b6f431777ee1fc1a1a701d3351660ea276321cea9d6a3f00def177c6da41e30c76970f684a29a2e26558b90fa6e43527d41af7e9598235
|
7
|
+
data.tar.gz: 475aeb08d49dcbfd0c45c40181546c96c531f8d1772a253c64d3314337d65380b08d3c9a718e08c8c9aedc68396585e7e951c2e7a0013e2f503b3972367d38df
|
data/.github/workflows/specs.yml
CHANGED
@@ -1,28 +1,32 @@
|
|
1
1
|
name: Specs
|
2
|
+
|
2
3
|
on:
|
3
4
|
push:
|
4
5
|
branches: [ master ]
|
5
6
|
pull_request:
|
6
7
|
branches: [ master ]
|
8
|
+
|
7
9
|
jobs:
|
8
10
|
test:
|
9
11
|
strategy:
|
10
12
|
fail-fast: false
|
11
13
|
matrix:
|
12
14
|
os: [ubuntu-latest]
|
13
|
-
ruby: [
|
15
|
+
ruby: ['3.0', '3.1', '3.2', '3.3', '3.4']
|
14
16
|
runs-on: ${{ matrix.os }}
|
15
17
|
steps:
|
16
|
-
- uses: actions/checkout@
|
18
|
+
- uses: actions/checkout@v4
|
17
19
|
- name: Install dependencies
|
18
20
|
run: sudo apt-get update -qq && sudo apt-get install libpcap-dev -qq
|
19
21
|
- name: Set up Ruby
|
20
22
|
uses: ruby/setup-ruby@v1
|
21
23
|
with:
|
22
24
|
ruby-version: ${{ matrix.ruby }}
|
23
|
-
- name:
|
25
|
+
- name: Install Gems
|
24
26
|
run: |
|
25
27
|
bundle config set path 'vendor/bundle'
|
26
28
|
bundle config set --local without noci
|
27
29
|
bundle install
|
30
|
+
- name: Run tests
|
31
|
+
run: |
|
28
32
|
bundle exec rake
|
data/.rubocop.yml
CHANGED
@@ -1,21 +1,39 @@
|
|
1
|
-
|
1
|
+
plugins:
|
2
2
|
- rubocop-performance
|
3
3
|
AllCops:
|
4
|
-
TargetRubyVersion:
|
4
|
+
TargetRubyVersion: "3.0"
|
5
|
+
NewCops: enable
|
6
|
+
Exclude:
|
7
|
+
- .git/**/*
|
8
|
+
- spec/**/*
|
9
|
+
- vendor/**/*
|
5
10
|
Layout/LineLength:
|
6
|
-
|
11
|
+
Enabled: false
|
7
12
|
Layout/SpaceAroundEqualsInParameterDefault:
|
8
13
|
EnforcedStyle: no_space
|
9
14
|
Lint/EmptyWhen:
|
10
15
|
Enabled: false
|
11
16
|
Lint/Void:
|
12
17
|
Enabled: false
|
13
|
-
Metrics:
|
18
|
+
Metrics/AbcSize:
|
19
|
+
Max: 20
|
20
|
+
Metrics/ClassLength:
|
21
|
+
Max: 200
|
22
|
+
Metrics/MethodLength:
|
23
|
+
Max: 20
|
24
|
+
Metrics/ParameterLists:
|
25
|
+
MaxOptionalParameters: 4
|
26
|
+
Naming/FileName:
|
27
|
+
Enabled: false
|
28
|
+
Style/AccessModifierDeclarations:
|
14
29
|
Enabled: false
|
15
30
|
Style/AsciiComments:
|
16
31
|
Enabled: false
|
17
32
|
Style/ClassAndModuleChildren:
|
18
|
-
|
33
|
+
Enabled: false
|
34
|
+
Style/Documentation:
|
35
|
+
# Too many false positives!
|
36
|
+
Enabled: false
|
19
37
|
Style/Encoding:
|
20
38
|
Enabled: false
|
21
39
|
Style/EvalWithLocation:
|
@@ -23,7 +41,7 @@ Style/EvalWithLocation:
|
|
23
41
|
Style/FormatString:
|
24
42
|
EnforcedStyle: percent
|
25
43
|
Style/FormatStringToken:
|
26
|
-
|
44
|
+
MaxUnannotatedPlaceholdersAllowed: 3
|
27
45
|
Style/PerlBackrefs:
|
28
46
|
Enabled: false
|
29
47
|
Style/RedundantSelf:
|
data/Gemfile
CHANGED
@@ -1,14 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
5
|
gemspec
|
4
6
|
|
5
7
|
gem 'bundler', '>= 1.17', '< 3'
|
6
|
-
|
7
|
-
|
8
|
+
|
9
|
+
group :development do
|
10
|
+
gem 'rake', '~>13.0', require: false
|
11
|
+
gem 'rspec', '~>3.13'
|
12
|
+
end
|
8
13
|
|
9
14
|
group :noci do
|
10
|
-
gem 'rubocop', '~> 1.
|
11
|
-
gem 'rubocop-performance', '~> 1.
|
12
|
-
gem '
|
13
|
-
gem '
|
15
|
+
gem 'rubocop', '~> 1.12', require: false
|
16
|
+
gem 'rubocop-performance', '~> 1.13', require: false
|
17
|
+
gem 'ruby-lsp', require: false
|
18
|
+
gem 'ruby-lsp-rspec', require: false
|
19
|
+
gem 'simplecov', '~> 0.21', require: false
|
20
|
+
gem 'yard', '~> 0.9', require: false
|
14
21
|
end
|
data/README.md
CHANGED
@@ -3,13 +3,15 @@
|
|
3
3
|
|
4
4
|
# packetgen-plugin-ipsec
|
5
5
|
|
6
|
-
**Warning:** this repository is a work-in-progress. It will be available with packetgen3.
|
7
|
-
|
8
6
|
This is a plugin for [PacketGen gem](https://github.com/sdaubert/packetgen). It adds two protocols:
|
9
7
|
|
10
8
|
* `PacketGen::Plugin::ESP`: IP Encapsulating Security Payload ([RFC 4303](https://tools.ietf.org/html/rfc4303)),
|
11
9
|
* `PacketGen::Plugin::IKE`: Internet Key Exchange v2 ([RFC 7296](https://tools.ietf.org/html/rfc7296)).
|
12
10
|
|
11
|
+
Versions 1.0.x are compatible with PacketGen 3.x.
|
12
|
+
|
13
|
+
Versions 1.1.x are compatible with PacketGen 4.x.
|
14
|
+
|
13
15
|
## Installation
|
14
16
|
|
15
17
|
Add this line to your application's Gemfile:
|
@@ -20,11 +22,15 @@ gem 'packetgen-plugin-ipsec'
|
|
20
22
|
|
21
23
|
And then execute:
|
22
24
|
|
23
|
-
|
25
|
+
```bash
|
26
|
+
bundle
|
27
|
+
```
|
24
28
|
|
25
29
|
Or install it yourself as:
|
26
30
|
|
27
|
-
|
31
|
+
```bash
|
32
|
+
gem install packetgen-plugin-ipsec
|
33
|
+
```
|
28
34
|
|
29
35
|
## Usage
|
30
36
|
|
@@ -86,7 +92,7 @@ pkt.to_w
|
|
86
92
|
|
87
93
|
## See also
|
88
94
|
|
89
|
-
API documentation: http://www.rubydoc.info/gems/packetgen-plugin-ipsec
|
95
|
+
API documentation: <http://www.rubydoc.info/gems/packetgen-plugin-ipsec>
|
90
96
|
|
91
97
|
## License
|
92
98
|
|
@@ -94,4 +100,4 @@ MIT License (see [LICENSE](https://github.com/sdaubert/packetgen-plugin-ipsec/bl
|
|
94
100
|
|
95
101
|
## Contributing
|
96
102
|
|
97
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/sdaubert/packetgen-plugin-ipsec
|
103
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/sdaubert/packetgen-plugin-ipsec>.
|
@@ -72,5 +72,37 @@ module PacketGen::Plugin
|
|
72
72
|
@intg&.update(data)
|
73
73
|
@conf.update(data)
|
74
74
|
end
|
75
|
+
|
76
|
+
# Compute and set IV for deciphering mode
|
77
|
+
# @param [BinStruct::String] salt
|
78
|
+
# @param [String] msg ciphered message
|
79
|
+
# @return [String] iv
|
80
|
+
def compute_iv_for_decrypting(salt, msg)
|
81
|
+
case confidentiality_mode
|
82
|
+
when 'gcm'
|
83
|
+
iv = msg.slice!(0, 8)
|
84
|
+
real_iv = salt + iv
|
85
|
+
when 'cbc'
|
86
|
+
@conf.padding = 0
|
87
|
+
real_iv = iv = msg.slice!(0, 16)
|
88
|
+
when 'ctr'
|
89
|
+
iv = msg.slice!(0, 8)
|
90
|
+
real_iv = salt + iv + [1].pack('N')
|
91
|
+
else
|
92
|
+
real_iv = iv = msg.slice!(0, 16)
|
93
|
+
end
|
94
|
+
@conf.iv = real_iv
|
95
|
+
iv
|
96
|
+
end
|
97
|
+
|
98
|
+
# Compute and set real IV for ciphering mode
|
99
|
+
# @param [String] iv IV to use
|
100
|
+
# @param [String] salt salt to use
|
101
|
+
# @return [void]
|
102
|
+
def compute_iv_for_encrypting(iv, salt) # rubocop:disable Naming/MethodParameterName
|
103
|
+
real_iv = salt.b + iv.b
|
104
|
+
real_iv += [1].pack('N') if confidentiality_mode == 'ctr'
|
105
|
+
@conf.iv = real_iv
|
106
|
+
end
|
75
107
|
end
|
76
108
|
end
|
data/lib/packetgen/plugin/esp.rb
CHANGED
@@ -7,14 +7,16 @@
|
|
7
7
|
|
8
8
|
require_relative 'crypto'
|
9
9
|
|
10
|
+
# rubocop:disable Metrics/ClassLength
|
11
|
+
|
10
12
|
module PacketGen::Plugin
|
11
13
|
# A ESP header consists of:
|
12
|
-
# * a Security Parameters Index (#{spi}, {
|
14
|
+
# * a Security Parameters Index (#{spi}, {BinStruct::Int32} type),
|
13
15
|
# * a Sequence Number ({#sn}, +Int32+ type),
|
14
16
|
# * a {#body} (variable length),
|
15
17
|
# * an optional TFC padding ({#tfc}, variable length),
|
16
18
|
# * an optional {#padding} (to align ESP on 32-bit boundary, variable length),
|
17
|
-
# * a {#pad_length} ({
|
19
|
+
# * a {#pad_length} ({BinStruct::Int8}),
|
18
20
|
# * a Next header field ({#next}, +Int8+),
|
19
21
|
# * and an optional Integrity Check Value ({#icv}, variable length).
|
20
22
|
#
|
@@ -78,34 +80,34 @@ module PacketGen::Plugin
|
|
78
80
|
# @!attribute spi
|
79
81
|
# 32-bit Security Parameter Index
|
80
82
|
# @return [Integer]
|
81
|
-
|
83
|
+
define_attr :spi, BinStruct::Int32
|
82
84
|
# @!attribute sn
|
83
85
|
# 32-bit Sequence Number
|
84
86
|
# @return [Integer]
|
85
|
-
|
87
|
+
define_attr :sn, BinStruct::Int32
|
86
88
|
# @!attribute body
|
87
|
-
# @return [
|
88
|
-
|
89
|
+
# @return [BinStruct::String,PacketGen::Header::Base]
|
90
|
+
define_attr :body, BinStruct::String
|
89
91
|
# @!attribute tfc
|
90
92
|
# Traffic Flow Confidentiality padding
|
91
|
-
# @return [
|
92
|
-
|
93
|
+
# @return [BinStruct::String,PacketGen::Header::Base]
|
94
|
+
define_attr :tfc, BinStruct::String
|
93
95
|
# @!attribute padding
|
94
96
|
# ESP padding
|
95
|
-
# @return [
|
96
|
-
|
97
|
+
# @return [BinStruct::String,PacketGen::Header::Base]
|
98
|
+
define_attr :padding, BinStruct::String
|
97
99
|
# @!attribute pad_length
|
98
100
|
# 8-bit padding length
|
99
101
|
# @return [Integer]
|
100
|
-
|
102
|
+
define_attr :pad_length, BinStruct::Int8
|
101
103
|
# @!attribute next
|
102
104
|
# 8-bit next protocol value
|
103
105
|
# @return [Integer]
|
104
|
-
|
106
|
+
define_attr :next, BinStruct::Int8
|
105
107
|
# @!attribute icv
|
106
108
|
# Integrity Check Value
|
107
|
-
# @return [
|
108
|
-
|
109
|
+
# @return [BinStruct::String,PacketGen::Header::Base]
|
110
|
+
define_attr :icv, BinStruct::String
|
109
111
|
|
110
112
|
# ICV (Integrity Check Value) length
|
111
113
|
# @return [Integer]
|
@@ -138,15 +140,14 @@ module PacketGen::Plugin
|
|
138
140
|
def read(str)
|
139
141
|
return self if str.nil?
|
140
142
|
|
141
|
-
|
142
|
-
self[:spi].read
|
143
|
-
self[:sn].read
|
144
|
-
self[:
|
145
|
-
self[:
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
self[:icv].read str[-@icv_length, @icv_length] if @icv_length
|
143
|
+
str = str.b
|
144
|
+
self[:spi].read(str[0, 4])
|
145
|
+
self[:sn].read(str[4, 4])
|
146
|
+
self[:tfc].read('')
|
147
|
+
self[:padding].read('')
|
148
|
+
|
149
|
+
read_icv_dependent_fields(str[8..])
|
150
|
+
read_icv(str)
|
150
151
|
self
|
151
152
|
end
|
152
153
|
|
@@ -177,72 +178,20 @@ module PacketGen::Plugin
|
|
177
178
|
# @option options [OpenSSL::HMAC] :intmode integrity mode to use with a
|
178
179
|
# confidentiality-only cipher. Only HMAC are supported.
|
179
180
|
# @return [self]
|
180
|
-
def encrypt!(cipher, iv, options={})
|
181
|
+
def encrypt!(cipher, iv, options={}) # rubocop:disable Naming/MethodParameterName
|
181
182
|
opt = { salt: '', tfc_size: 1444 }.merge(options)
|
182
183
|
|
183
184
|
set_crypto cipher, opt[:intmode]
|
184
|
-
|
185
|
-
real_iv = force_binary(opt[:salt]) + force_binary(iv)
|
186
|
-
real_iv += [1].pack('N') if confidentiality_mode == 'ctr'
|
187
|
-
cipher.iv = real_iv
|
185
|
+
compute_iv_for_encrypting iv, opt[:salt]
|
188
186
|
|
189
187
|
authenticate_esp_header_if_needed options, iv
|
190
188
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
self.pad_length = (16 - (cipher_len % 16)) % 16
|
195
|
-
else
|
196
|
-
mod4 = to_s.size % 4
|
197
|
-
self.pad_length = 4 - mod4 if mod4.positive?
|
198
|
-
end
|
199
|
-
|
200
|
-
if opt[:pad_length]
|
201
|
-
self.pad_length = opt[:pad_length]
|
202
|
-
padding = force_binary(opt[:padding] || (1..self.pad_length).to_a.pack('C*'))
|
203
|
-
self[:padding].read padding
|
204
|
-
else
|
205
|
-
padding = force_binary(opt[:padding] || (1..self.pad_length).to_a.pack('C*'))
|
206
|
-
self[:padding].read padding[0...self.pad_length]
|
207
|
-
end
|
208
|
-
|
209
|
-
tfc = ''
|
210
|
-
if opt[:tfc]
|
211
|
-
tfc_size = opt[:tfc_size] - self[:body].sz
|
212
|
-
if tfc_size.positive?
|
213
|
-
tfc_size = case confidentiality_mode
|
214
|
-
when 'cbc'
|
215
|
-
(tfc_size / 16) * 16
|
216
|
-
else
|
217
|
-
(tfc_size / 4) * 4
|
218
|
-
end
|
219
|
-
tfc = force_binary("\0" * tfc_size)
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
msg = self[:body].to_s + tfc
|
224
|
-
msg += self[:padding].to_s + self[:pad_length].to_s + self[:next].to_s
|
225
|
-
enc_msg = encipher(msg)
|
226
|
-
# as padding is used to pad for CBC mode, this is unused
|
227
|
-
cipher.final
|
228
|
-
|
229
|
-
self[:body] = PacketGen::Types::String.new.read(iv)
|
230
|
-
self[:body] << enc_msg[0..-3]
|
231
|
-
self[:pad_length].read enc_msg[-2]
|
232
|
-
self[:next].read enc_msg[-1]
|
233
|
-
|
234
|
-
# reset padding field as it has no sense in encrypted ESP
|
235
|
-
self[:padding].read ''
|
189
|
+
encrypt_set_pad_length
|
190
|
+
encrypt_set_padding(opt)
|
191
|
+
encrypt_body(opt, iv)
|
236
192
|
|
237
193
|
set_esp_icv_if_needed
|
238
|
-
|
239
|
-
# Remove enciphered headers from packet
|
240
|
-
id = header_id(self)
|
241
|
-
if id < packet.headers.size - 1
|
242
|
-
(packet.headers.size - 1).downto(id + 1) do |index|
|
243
|
-
packet.headers.delete_at index
|
244
|
-
end
|
245
|
-
end
|
194
|
+
remove_enciphered_packets
|
246
195
|
|
247
196
|
self
|
248
197
|
end
|
@@ -265,51 +214,38 @@ module PacketGen::Plugin
|
|
265
214
|
opt = { salt: '', parse: true }.merge(options)
|
266
215
|
|
267
216
|
set_crypto cipher, opt[:intmode]
|
268
|
-
|
269
|
-
case confidentiality_mode
|
270
|
-
when 'gcm'
|
271
|
-
iv = self[:body].slice!(0, 8)
|
272
|
-
real_iv = opt[:salt] + iv
|
273
|
-
when 'cbc'
|
274
|
-
cipher.padding = 0
|
275
|
-
real_iv = iv = self[:body].slice!(0, 16)
|
276
|
-
when 'ctr'
|
277
|
-
iv = self[:body].slice!(0, 8)
|
278
|
-
real_iv = opt[:salt] + iv + [1].pack('N')
|
279
|
-
else
|
280
|
-
real_iv = iv = self[:body].slice!(0, 16)
|
281
|
-
end
|
282
|
-
cipher.iv = real_iv
|
283
|
-
|
217
|
+
iv = compute_iv_for_decrypting(opt[:salt], self[:body])
|
284
218
|
if authenticated? && (@icv_length.zero? || opt[:icv_length])
|
285
|
-
|
286
|
-
|
287
|
-
@icv_length = opt[:icv_length].to_i
|
288
|
-
# reread ESP to handle new ICV size
|
289
|
-
msg = self[:body].to_s + self[:pad_length].to_s
|
290
|
-
msg += self[:next].to_s
|
291
|
-
self[:icv].read msg.slice!(-@icv_length, @icv_length)
|
292
|
-
self[:body].read msg[0..-3]
|
293
|
-
self[:pad_length].read msg[-2]
|
294
|
-
self[:next].read msg[-1]
|
219
|
+
check_icv_length(opt)
|
220
|
+
decrypt_format_packet
|
295
221
|
end
|
296
|
-
|
297
222
|
authenticate_esp_header_if_needed options, iv, icv
|
298
223
|
private_decrypt opt
|
299
224
|
end
|
300
225
|
|
301
226
|
private
|
302
227
|
|
228
|
+
def read_icv_dependent_fields(str)
|
229
|
+
body_end = -@icv_length - 2
|
230
|
+
self[:body].read str[0...body_end]
|
231
|
+
self[:pad_length].read str[body_end, 1]
|
232
|
+
self[:next].read str[body_end + 1, 1]
|
233
|
+
end
|
234
|
+
|
235
|
+
def read_icv(str)
|
236
|
+
self[:icv].read str[-@icv_length, @icv_length] if @icv_length
|
237
|
+
end
|
238
|
+
|
303
239
|
def get_auth_data(opt)
|
304
240
|
ad = self[:spi].to_s
|
305
241
|
if opt[:esn]
|
306
|
-
@esn =
|
242
|
+
@esn = BinStruct::Int32.new(value: opt[:esn])
|
307
243
|
ad << @esn.to_s if @conf.authenticated?
|
308
244
|
end
|
309
245
|
ad << self[:sn].to_s
|
310
246
|
end
|
311
247
|
|
312
|
-
def authenticate_esp_header_if_needed(opt, iv, icv=nil)
|
248
|
+
def authenticate_esp_header_if_needed(opt, iv, icv=nil) # rubocop:disable Naming/MethodParameterName
|
313
249
|
if @conf.authenticated?
|
314
250
|
@conf.auth_tag = icv if icv
|
315
251
|
@conf.auth_data = get_auth_data(opt)
|
@@ -323,6 +259,65 @@ module PacketGen::Plugin
|
|
323
259
|
end
|
324
260
|
end
|
325
261
|
|
262
|
+
def encrypt_set_pad_length
|
263
|
+
case confidentiality_mode
|
264
|
+
when 'cbc'
|
265
|
+
cipher_len = self[:body].sz + 2
|
266
|
+
self.pad_length = (16 - (cipher_len % 16)) % 16
|
267
|
+
else
|
268
|
+
mod4 = to_s.size % 4
|
269
|
+
self.pad_length = 4 - mod4 if mod4.positive?
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def encrypt_set_padding(opt)
|
274
|
+
if opt[:pad_length]
|
275
|
+
self.pad_length = opt[:pad_length]
|
276
|
+
padding = opt[:padding] || (1..self.pad_length).to_a.pack('C*')
|
277
|
+
else
|
278
|
+
padding = opt[:padding] || (1..self.pad_length).to_a.pack('C*')
|
279
|
+
padding = padding[0...self.pad_length]
|
280
|
+
end
|
281
|
+
self[:padding].read(padding)
|
282
|
+
end
|
283
|
+
|
284
|
+
def generate_tfc(opt)
|
285
|
+
tfc = ''
|
286
|
+
return tfc unless opt[:tfc]
|
287
|
+
|
288
|
+
tfc_size = opt[:tfc_size] - self[:body].sz
|
289
|
+
if tfc_size.positive?
|
290
|
+
tfc_size = case confidentiality_mode
|
291
|
+
when 'cbc'
|
292
|
+
(tfc_size / 16) * 16
|
293
|
+
else
|
294
|
+
(tfc_size / 4) * 4
|
295
|
+
end
|
296
|
+
tfc = "\0".b * tfc_size
|
297
|
+
end
|
298
|
+
tfc
|
299
|
+
end
|
300
|
+
|
301
|
+
def encrypt_body(opt, iv) # rubocop:disable Naming/MethodParameterName
|
302
|
+
msg = self[:body].to_s + generate_tfc(opt)
|
303
|
+
msg += self[:padding].to_s + self[:pad_length].to_s + self[:next].to_s
|
304
|
+
enc_msg = encipher(msg)
|
305
|
+
# as padding is used to pad for CBC mode, this is unused
|
306
|
+
@conf.final
|
307
|
+
|
308
|
+
encrypt_set_encrypted_fields(enc_msg, iv)
|
309
|
+
end
|
310
|
+
|
311
|
+
def encrypt_set_encrypted_fields(msg, iv) # rubocop:disable Naming/MethodParameterName
|
312
|
+
self[:body] = BinStruct::String.new.read(iv)
|
313
|
+
self[:body] << msg[0..-3]
|
314
|
+
self[:pad_length].read msg[-2]
|
315
|
+
self[:next].read msg[-1]
|
316
|
+
|
317
|
+
# reset padding field as it has no sense in encrypted ESP
|
318
|
+
self[:padding].read ''
|
319
|
+
end
|
320
|
+
|
326
321
|
def set_esp_icv_if_needed
|
327
322
|
return unless authenticated?
|
328
323
|
|
@@ -333,29 +328,62 @@ module PacketGen::Plugin
|
|
333
328
|
end
|
334
329
|
end
|
335
330
|
|
336
|
-
def
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
331
|
+
def remove_enciphered_packets
|
332
|
+
id = header_id(self)
|
333
|
+
return if id >= packet.headers.size - 1
|
334
|
+
|
335
|
+
(packet.headers.size - 1).downto(id + 1) do |index|
|
336
|
+
packet.headers.delete_at index
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def check_icv_length(opt)
|
341
|
+
raise PacketGen::ParseError, 'unknown ICV size' unless opt[:icv_length]
|
342
|
+
|
343
|
+
@icv_length = opt[:icv_length].to_i
|
344
|
+
end
|
341
345
|
|
346
|
+
def decrypt_format_packet
|
347
|
+
# reread ESP to handle new ICV size
|
348
|
+
msg = self[:body].to_s + self[:pad_length].to_s
|
349
|
+
msg << self[:next].to_s
|
350
|
+
read_icv_dependent_fields(msg)
|
351
|
+
read_icv(msg)
|
352
|
+
end
|
353
|
+
|
354
|
+
def private_decrypt(options)
|
355
|
+
plain_msg = decrypt_body
|
342
356
|
# check authentication tag
|
343
357
|
return false if authenticated? && !authenticate!
|
344
358
|
|
345
|
-
|
359
|
+
new_pkt = fill_decrypted_fields_and_generate_plain_packet(plain_msg)
|
360
|
+
packet.encapsulate new_pkt if options[:parse] && !new_pkt.nil?
|
361
|
+
true
|
362
|
+
end
|
363
|
+
|
364
|
+
def decrypt_body
|
365
|
+
msg = self.body.to_s
|
366
|
+
msg += self.padding + self[:pad_length].to_s + self[:next].to_s
|
367
|
+
decipher(msg)
|
368
|
+
end
|
369
|
+
|
370
|
+
def fill_decrypted_fields_and_generate_plain_packet(plain_msg)
|
346
371
|
self[:body].read plain_msg[0..-3]
|
347
372
|
self[:pad_length].read plain_msg[-2]
|
348
373
|
self[:next].read plain_msg[-1]
|
349
374
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
375
|
+
fill_padding_field
|
376
|
+
generate_plain_pkt
|
377
|
+
end
|
378
|
+
|
379
|
+
def fill_padding_field
|
380
|
+
return unless self.pad_length.positive?
|
355
381
|
|
356
|
-
|
357
|
-
|
358
|
-
|
382
|
+
len = self.pad_length
|
383
|
+
self[:padding].read self[:body].slice!(-len, len)
|
384
|
+
end
|
385
|
+
|
386
|
+
def generate_plain_pkt # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
359
387
|
case self.next
|
360
388
|
when 4 # IPv4
|
361
389
|
pkt = PacketGen::Packet.parse(body, first_header: 'IP')
|
@@ -381,19 +409,19 @@ module PacketGen::Plugin
|
|
381
409
|
encap_length = self[:body].sz
|
382
410
|
else
|
383
411
|
# Unmanaged encapsulated protocol
|
412
|
+
pkt = nil
|
384
413
|
encap_length = self[:body].sz
|
385
414
|
end
|
386
415
|
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
end
|
416
|
+
remove_tfc_if_needed(encap_length)
|
417
|
+
pkt
|
418
|
+
end
|
391
419
|
|
392
|
-
|
393
|
-
|
394
|
-
end
|
420
|
+
def remove_tfc_if_needed(real_length)
|
421
|
+
return if real_length == self[:body].sz
|
395
422
|
|
396
|
-
|
423
|
+
tfc_len = self[:body].sz - real_length
|
424
|
+
self[:tfc].read self[:body].slice!(real_length, tfc_len)
|
397
425
|
end
|
398
426
|
end
|
399
427
|
|
@@ -405,7 +433,7 @@ module PacketGen::Plugin
|
|
405
433
|
lambda { |f|
|
406
434
|
(f.dport == ESP::UDP_PORT ||
|
407
435
|
f.sport == ESP::UDP_PORT) &&
|
408
|
-
|
436
|
+
BinStruct::Int32.new.read(f.body[0..3]).to_i.positive?
|
409
437
|
}]
|
410
438
|
ESP.bind PacketGen::Header::IP, next: 4
|
411
439
|
ESP.bind PacketGen::Header::IPv6, next: 41
|
@@ -414,3 +442,4 @@ module PacketGen::Plugin
|
|
414
442
|
ESP.bind PacketGen::Header::ICMP, next: PacketGen::Header::ICMP::IP_PROTOCOL
|
415
443
|
ESP.bind PacketGen::Header::ICMPv6, next: PacketGen::Header::ICMPv6::IP_PROTOCOL
|
416
444
|
end
|
445
|
+
# rubocop:enable Metrics/ClassLength
|