From 17e8c6cc34a9a22e440b1113785893d5bc32507c Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Tue, 10 Apr 2018 19:49:59 +0200 Subject: [PATCH 01/11] snabbmark esp: add rudimentary PMU analysis --- src/program/snabbmark/snabbmark.lua | 42 +++++++++++++++++++---------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/program/snabbmark/snabbmark.lua b/src/program/snabbmark/snabbmark.lua index c33d815735..5432b907b0 100644 --- a/src/program/snabbmark/snabbmark.lua +++ b/src/program/snabbmark/snabbmark.lua @@ -11,6 +11,14 @@ local lib = require("core.lib") local ffi = require("ffi") local C = ffi.C +local pmu = require('lib.pmu') +local has_pmu_counters, err = pmu.is_available() +if not has_pmu_counters then + io.stderr:write('No PMU available: '..err..'\n') +else + pmu.setup() +end + function run (args) local command = table.remove(args, 1) if command == 'basic1' and #args == 1 then @@ -371,9 +379,16 @@ function esp (npackets, packet_size, mode, direction, profile) end if direction == "encapsulate" then if profile then profiler.start(profile) end + local function test_encapsulate () + for i = 1, npackets do + packet.free(encap(packet.clone(plain))) + end + end local start = C.get_monotonic_time() - for i = 1, npackets do - packet.free(encap(packet.clone(plain))) + if has_pmu_counters then + pmu.profile(test_encapsulate) + else + test_encapsulate() end local finish = C.get_monotonic_time() if profile then profiler.stop() end @@ -382,12 +397,19 @@ function esp (npackets, packet_size, mode, direction, profile) :format(packet_size, gbits(bps))) else local encapsulated = encap(packet.clone(plain)) + local function test_decapsulate () + for i = 1, npackets do + packet.free(decap(packet.clone(encapsulated))) + dec.seq.no = 0 + dec.window[0] = 0 + end + end if profile then profiler.start(profile) end local start = C.get_monotonic_time() - for i = 1, npackets do - packet.free(decap(packet.clone(encapsulated))) - dec.seq.no = 0 - dec.window[0] = 0 + if has_pmu_counters then + pmu.profile(test_decapsulate) + else + test_decapsulate() end local finish = C.get_monotonic_time() if profile then profiler.stop() end @@ -397,14 +419,6 @@ function esp (npackets, packet_size, mode, direction, profile) end end -local pmu = require('lib.pmu') -local has_pmu_counters, err = pmu.is_available() -if not has_pmu_counters then - io.stderr:write('No PMU available: '..err..'\n') -end - -if has_pmu_counters then pmu.setup() end - local function measure(f, iterations) local set if has_pmu_counters then set = pmu.new_counter_set() end From 461f195a22767b16c4f268be510f18a5c6cded62 Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Tue, 10 Apr 2018 21:45:13 +0200 Subject: [PATCH 02/11] lib.ipsec.aes_128_gcm: add rudimentary PMU profiling to selftest --- src/lib/ipsec/aes_128_gcm.lua | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/lib/ipsec/aes_128_gcm.lua b/src/lib/ipsec/aes_128_gcm.lua index 0a415d8dbd..3d3362805f 100644 --- a/src/lib/ipsec/aes_128_gcm.lua +++ b/src/lib/ipsec/aes_128_gcm.lua @@ -256,23 +256,35 @@ function selftest () "Authentication failed.") end -- Microbenchmarks. + local pmu = require("lib.pmu") + local has_pmu_counters, err = pmu.is_available() + if not has_pmu_counters then + io.stderr:write('No PMU available: '..err..'\n') + else + pmu.setup() + end + local profile = (has_pmu_counters and pmu.profile) or function (f) f() end local length = 1000 * 1000 * 100 -- 100MB local gcm = aes_128_gcm:new(0x0, "00000000000000000000000000000000", "00000000") local p = ffi.new("uint8_t[?]", length + gcm.AUTH_SIZE) local start = C.get_monotonic_time() - ASM.aesni_gcm_enc_avx_gen4(gcm.gcm_data, - p, p, length, - u8_ptr(gcm.iv:header_ptr()), - p, 0, -- No AAD - p + length, gcm.AUTH_SIZE) + profile(function () + ASM.aesni_gcm_enc_avx_gen4(gcm.gcm_data, + p, p, length, + u8_ptr(gcm.iv:header_ptr()), + p, 0, -- No AAD + p + length, gcm.AUTH_SIZE) + end) local finish = C.get_monotonic_time() print("Encrypted", length, "bytes in", finish-start, "seconds") local start = C.get_monotonic_time() - ASM.aesni_gcm_dec_avx_gen4(gcm.gcm_data, - p, p, length, - u8_ptr(gcm.iv:header_ptr()), - p, 0, -- No AAD - p + length, gcm.AUTH_SIZE) + profile(function () + ASM.aesni_gcm_dec_avx_gen4(gcm.gcm_data, + p, p, length, + u8_ptr(gcm.iv:header_ptr()), + p, 0, -- No AAD + p + length, gcm.AUTH_SIZE) + end) local finish = C.get_monotonic_time() print("Decrypted", length, "bytes in", finish-start, "seconds") -- Test aes_128_block with vectors from From 9d14b98edac1326c3e06bdfefc3873d968e43507 Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Mon, 2 Apr 2018 15:19:47 +0200 Subject: [PATCH 03/11] snabbmark esp: fix bug where packets of wrong size were constructed ...for transport mode when run without an explicit mode. --- src/program/snabbmark/snabbmark.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/program/snabbmark/snabbmark.lua b/src/program/snabbmark/snabbmark.lua index 5432b907b0..8818ca2631 100644 --- a/src/program/snabbmark/snabbmark.lua +++ b/src/program/snabbmark/snabbmark.lua @@ -359,7 +359,7 @@ function esp (npackets, packet_size, mode, direction, profile) ip:payload_length(payload_size) d:payload(payload, payload_size) d:push(ip) - if not mode == "tunnel" then + if not (mode == "tunnel") then local eth = ethernet:new({type=0x86dd}) d:push(eth) end From 7f75dc10184418d3d93378d75f4a26ab4a179805 Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Mon, 2 Apr 2018 16:09:28 +0200 Subject: [PATCH 04/11] snabbmark esp: minor changes * add a note that explains performance differences between esp transport and tunnel modes * explicitly return a single value from `decap' in tunnel mode (because of that thing where LuaJIT can trip over this) ...these changes are mostly notes to prevent future selfs from wondering about this again. --- src/program/snabbmark/README | 4 ++++ src/program/snabbmark/snabbmark.lua | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/program/snabbmark/README b/src/program/snabbmark/README index 23e074babf..6bbd3ac667 100644 --- a/src/program/snabbmark/README +++ b/src/program/snabbmark/README @@ -45,6 +45,10 @@ Usage: Optionally, a LuaJIT profiler option string can be supplied as , which will cause the benchmark run to be profiled accordingly. + Note: transport mode may generally score better because it has to + encapsulate 40 bytes less per packet because of the enclosed IPv6 header + in tunnel mode, and this micro-benchmark measures end-to-end throughput. + snabbmark hash [] Benchmark hash functions used for internal data structures. diff --git a/src/program/snabbmark/snabbmark.lua b/src/program/snabbmark/snabbmark.lua index 8818ca2631..4d5b75a946 100644 --- a/src/program/snabbmark/snabbmark.lua +++ b/src/program/snabbmark/snabbmark.lua @@ -372,7 +372,7 @@ function esp (npackets, packet_size, mode, direction, profile) local encap, decap if mode == "tunnel" then encap = function (p) return enc:encapsulate_tunnel(p, 41) end - decap = function (p) return dec:decapsulate_tunnel(p) end + decap = function (p) return (dec:decapsulate_tunnel(p)) end else encap = function (p) return enc:encapsulate_transport6(p) end decap = function (p) return dec:decapsulate_transport6(p) end From bb72e66bdb02c80cb128b070a96644261cff64ae Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Mon, 2 Apr 2018 16:26:03 +0200 Subject: [PATCH 05/11] lib.ipsec: add missing licensing headers --- src/lib/ipsec/aes_128_gcm.lua | 5 ++++- src/lib/ipsec/aes_128_gcm_avx.dasl | 2 ++ src/lib/ipsec/esp.lua | 6 +++++- src/lib/ipsec/seq_no_t.lua | 5 ++++- src/lib/ipsec/track_seq_no.c | 2 ++ src/lib/ipsec/track_seq_no.h | 2 ++ 6 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/lib/ipsec/aes_128_gcm.lua b/src/lib/ipsec/aes_128_gcm.lua index 3d3362805f..5f4b82cc9f 100644 --- a/src/lib/ipsec/aes_128_gcm.lua +++ b/src/lib/ipsec/aes_128_gcm.lua @@ -1,4 +1,7 @@ -module(..., package.seeall) +-- Use of this source code is governed by the Apache 2.0 license; see COPYING. + +module(...,package.seeall) + local ffi = require("ffi") local C = ffi.C local ASM = require("lib.ipsec.aes_128_gcm_avx") diff --git a/src/lib/ipsec/aes_128_gcm_avx.dasl b/src/lib/ipsec/aes_128_gcm_avx.dasl index b4cae2b353..395e55ac0c 100644 --- a/src/lib/ipsec/aes_128_gcm_avx.dasl +++ b/src/lib/ipsec/aes_128_gcm_avx.dasl @@ -1,3 +1,5 @@ +-- Use of this source code is governed by the Apache 2.0 license; see COPYING. + -- Selected AES GCM routines, based heavily on the Intel IPsec code from: -- https://github.com/lukego/intel-ipsec/blob/master/code/avx2/gcm_avx_gen4.asm -- https://github.com/lukego/intel-ipsec/blob/master/code/gcm_defines.asm diff --git a/src/lib/ipsec/esp.lua b/src/lib/ipsec/esp.lua index e48659c561..0e45cddc02 100644 --- a/src/lib/ipsec/esp.lua +++ b/src/lib/ipsec/esp.lua @@ -1,3 +1,7 @@ +-- Use of this source code is governed by the Apache 2.0 license; see COPYING. + +module(...,package.seeall) + -- Implementation of IPsec ESP using AES-128-GCM with a 12 byte ICV and -- “Extended Sequence Number” (see RFC 4303 and RFC 4106). Provides -- address-family independent encapsulation/decapsulation routines for @@ -17,7 +21,7 @@ -- to remain correct. See the “Reassembly” section of RFC 4303 for details: -- https://tools.ietf.org/html/rfc4303#section-3.4.1 -- -module(..., package.seeall) + local header = require("lib.protocol.header") local datagram = require("lib.protocol.datagram") local ethernet = require("lib.protocol.ethernet") diff --git a/src/lib/ipsec/seq_no_t.lua b/src/lib/ipsec/seq_no_t.lua index 7f4e46da6c..ed9f7cc291 100644 --- a/src/lib/ipsec/seq_no_t.lua +++ b/src/lib/ipsec/seq_no_t.lua @@ -1,4 +1,7 @@ -module(..., package.seeall) +-- Use of this source code is governed by the Apache 2.0 license; see COPYING. + +module(...,package.seeall) + local ffi = require("ffi") -- Sequence number type with accessors for lower/upper order 32 bits diff --git a/src/lib/ipsec/track_seq_no.c b/src/lib/ipsec/track_seq_no.c index 78ae1c9ead..7fd2e89e24 100644 --- a/src/lib/ipsec/track_seq_no.c +++ b/src/lib/ipsec/track_seq_no.c @@ -1,3 +1,5 @@ +/* Use of this source code is governed by the Apache 2.0 license; see COPYING. */ + // See https://tools.ietf.org/html/rfc4303#page-38 #include diff --git a/src/lib/ipsec/track_seq_no.h b/src/lib/ipsec/track_seq_no.h index 5f11c4d49e..b44b5c1a26 100644 --- a/src/lib/ipsec/track_seq_no.h +++ b/src/lib/ipsec/track_seq_no.h @@ -1,2 +1,4 @@ +/* Use of this source code is governed by the Apache 2.0 license; see COPYING. */ + uint64_t track_seq_no (uint32_t, uint32_t, uint64_t, uint8_t *, uint32_t); int64_t check_seq_no (uint32_t, uint64_t, uint8_t *, uint32_t); From 53ae8bdf67d8bf77c1e53b16502e9ad5061c1293 Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Tue, 3 Apr 2018 14:42:03 +0200 Subject: [PATCH 06/11] lib.ipsec.esp: correct bogus note about IP fragment handling --- src/lib/ipsec/README.md | 2 ++ src/lib/ipsec/esp.lua | 10 +++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/lib/ipsec/README.md b/src/lib/ipsec/README.md index d4002fcb0e..7fe79c0570 100644 --- a/src/lib/ipsec/README.md +++ b/src/lib/ipsec/README.md @@ -6,6 +6,8 @@ transport modes. Currently, the only supported cipher is AES-GCM cipher with 128‑bit keys, 4 bytes of salt, and a 12 byte authentication code. These classes do not implement any key exchange protocol. +Note: the classes in this module do not reject IP fragments of any sort. + References: - [IPsec Wikipedia page](https://en.wikipedia.org/wiki/IPsec). diff --git a/src/lib/ipsec/esp.lua b/src/lib/ipsec/esp.lua index 0e45cddc02..219508c8ad 100644 --- a/src/lib/ipsec/esp.lua +++ b/src/lib/ipsec/esp.lua @@ -13,14 +13,10 @@ module(...,package.seeall) -- it is assumed to be an unrealistic scenario as it would take 584 years to -- overflow the counter when transmitting 10^9 packets per second. -- --- * decapsulate_transport6: Rejection of IP fragments is *not* implemented --- because `lib.protocol.ipv6' does not support fragmentation. E.g. --- fragments will be rejected because they can not be parsed as IPv6 --- packets. If however `lib.protocol.ipv6' were to be updated to be able to --- parse IP fragments this implementation would have to be updated as well --- to remain correct. See the “Reassembly” section of RFC 4303 for details: +-- * IP fragments are *not* rejected by the routines in this library, and are +-- expected to be handled prior to encapsulation/decapsulation. +-- See the “Reassembly” section of RFC 4303 for details: -- https://tools.ietf.org/html/rfc4303#section-3.4.1 --- local header = require("lib.protocol.header") local datagram = require("lib.protocol.datagram") From 531170a773da218afc17994742a7f49c4bd3b76f Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Mon, 2 Apr 2018 15:23:39 +0200 Subject: [PATCH 07/11] lib.ipsec.esp: avoid lib.protocol.* on the fast-path This avoids the potentially significant overhead of the lib.protocol.header abstractions during ESP encapsulation by using raw FFI casts instead. --- src/lib/ipsec/README.md | 3 +- src/lib/ipsec/esp.lua | 110 ++++++++++++++++++++-------------- src/lib/protocol/esp.lua | 50 ---------------- src/lib/protocol/esp_tail.lua | 48 --------------- 4 files changed, 66 insertions(+), 145 deletions(-) delete mode 100644 src/lib/protocol/esp.lua delete mode 100644 src/lib/protocol/esp_tail.lua diff --git a/src/lib/ipsec/README.md b/src/lib/ipsec/README.md index 7fe79c0570..cb8535b7d9 100644 --- a/src/lib/ipsec/README.md +++ b/src/lib/ipsec/README.md @@ -42,7 +42,8 @@ be a table with the following keys: default is 8. (`decrypt` only.) * `auditing` - *Optional.* A boolean value indicating whether to enable or disable “Auditing” as specified in RFC 4303. The default is `nil` (no - auditing). (`decrypt` only.) + auditing). (`decrypt` only. Note: source address, destination address and + flow ID are only logged when using `decapsulate_transport6`.) #### Tunnel mode diff --git a/src/lib/ipsec/esp.lua b/src/lib/ipsec/esp.lua index 219508c8ad..6ff78946dc 100644 --- a/src/lib/ipsec/esp.lua +++ b/src/lib/ipsec/esp.lua @@ -22,8 +22,6 @@ local header = require("lib.protocol.header") local datagram = require("lib.protocol.datagram") local ethernet = require("lib.protocol.ethernet") local ipv6 = require("lib.protocol.ipv6") -local esp = require("lib.protocol.esp") -local esp_tail = require("lib.protocol.esp_tail") local aes_128_gcm = require("lib.ipsec.aes_128_gcm") local seq_no_t = require("lib.ipsec.seq_no_t") local lib = require("core.lib") @@ -31,15 +29,36 @@ local ffi = require("ffi") local C = ffi.C local logger = lib.logger_new({ rate = 32, module = 'esp' }) +local htons, htonl, ntohl = lib.htons, lib.htonl, lib.ntohl + require("lib.ipsec.track_seq_no_h") local window_t = ffi.typeof("uint8_t[?]") PROTOCOL = 50 -- https://tools.ietf.org/html/rfc4303#section-2 +local ipv6_ptr_t = ffi.typeof("$ *", ipv6:ctype()) +local function ipv6_fl (ip) return bit.lshift(ntohl(ip.v_tc_fl), 12) end + +local esp_header_t = ffi.typeof( + [[struct { + uint32_t spi; + uint32_t seq_no; + } __attribute__((packed))]] +) +local esp_header_ptr_t = ffi.typeof("$ *", esp_header_t) + +local esp_trailer_t = ffi.typeof( + [[struct { + uint8_t pad_length; + uint8_t next_header; + } __attribute__((packed))]] +) +local esp_trailer_ptr_t = ffi.typeof("$ *", esp_trailer_t) + local ETHERNET_SIZE = ethernet:sizeof() local IPV6_SIZE = ipv6:sizeof() -local ESP_SIZE = esp:sizeof() -local ESP_TAIL_SIZE = esp_tail:sizeof() +local ESP_SIZE = ffi.sizeof(esp_header_t) +local ESP_TAIL_SIZE = ffi.sizeof(esp_trailer_t) local TRANSPORT6_PAYLOAD_OFFSET = ETHERNET_SIZE + IPV6_SIZE @@ -53,10 +72,7 @@ function esp_new (conf) cipher = aes_128_gcm:new(conf.spi, conf.key, conf.salt), spi = conf.spi, seq = ffi.new(seq_no_t), - pad_to = 4, -- minimal padding - esp = esp:new({}), - esp_tail = esp_tail:new({}), - ip = ipv6:new({}) -- for transport mode + pad_to = 4 -- minimal padding } o.ESP_CTEXT_OVERHEAD = o.cipher.IV_SIZE + ESP_TAIL_SIZE @@ -82,9 +98,9 @@ function encrypt:padding (length) end function encrypt:encode_esp_trailer (ptr, next_header, pad_length) - self.esp_tail:new_from_mem(ptr, ESP_TAIL_SIZE) - self.esp_tail:next_header(next_header) - self.esp_tail:pad_length(pad_length) + local esp_trailer = ffi.cast(esp_trailer_ptr_t, ptr) + esp_trailer.next_header = next_header + esp_trailer.pad_length = pad_length end function encrypt:encrypt_payload (ptr, length) @@ -94,9 +110,9 @@ function encrypt:encrypt_payload (ptr, length) end function encrypt:encode_esp_header (ptr) - self.esp:new_from_mem(ptr, ESP_SIZE) - self.esp:spi(self.spi) - self.esp:seq_no(self.seq:low()) + local esp_header = ffi.cast(esp_header_ptr_t, ptr) + esp_header.spi = htonl(self.spi) + esp_header.seq_no = htonl(self.seq:low()) ffi.copy(ptr + ESP_SIZE, self.seq, self.cipher.IV_SIZE) end @@ -109,16 +125,16 @@ end function encrypt:encapsulate_transport6 (p) if p.length < TRANSPORT6_PAYLOAD_OFFSET then return nil end + local ip = ffi.cast(ipv6_ptr_t, p.data + ETHERNET_SIZE) + local payload = p.data + TRANSPORT6_PAYLOAD_OFFSET local payload_length = p.length - TRANSPORT6_PAYLOAD_OFFSET local pad_length = self:padding(payload_length) local overhead = self.ESP_OVERHEAD + pad_length p = packet.resize(p, p.length + overhead) - self.ip:new_from_mem(p.data + ETHERNET_SIZE, IPV6_SIZE) - local tail = payload + payload_length + pad_length - self:encode_esp_trailer(tail, self.ip:next_header(), pad_length) + self:encode_esp_trailer(tail, ip.next_header, pad_length) local ctext_length = payload_length + pad_length + ESP_TAIL_SIZE self:encrypt_payload(payload, ctext_length) @@ -128,8 +144,8 @@ function encrypt:encapsulate_transport6 (p) self:encode_esp_header(payload) - self.ip:next_header(PROTOCOL) - self.ip:payload_length(payload_length + overhead) + ip.next_header = PROTOCOL + ip.payload_length = htons(payload_length + overhead) return p end @@ -187,14 +203,14 @@ function decrypt:new (conf) return setmetatable(o, {__index=decrypt}) end -function decrypt:decrypt_payload (ptr, length) +function decrypt:decrypt_payload (ptr, length, ip) -- NB: bounds check is performed by caller - local esp = self.esp:new_from_mem(ptr, esp:sizeof()) + local esp_header = ffi.cast(esp_header_ptr_t, ptr) local iv_start = ptr + ESP_SIZE local ctext_start = ptr + self.CTEXT_OFFSET local ctext_length = length - self.PLAIN_OVERHEAD - local seq_low = esp:seq_no() + local seq_low = ntohl(esp_header.seq_no) local seq_high = tonumber( C.check_seq_no(seq_low, self.seq.no, self.window, self.window_size) ) @@ -214,7 +230,7 @@ function decrypt:decrypt_payload (ptr, length) end if error then - self:audit(error) + self:audit(error, ntohl(esp_header.spi), seq_low, ip) return nil end @@ -223,12 +239,11 @@ function decrypt:decrypt_payload (ptr, length) seq_high, seq_low, self.seq.no, self.window, self.window_size ) - local esp_tail_start = ctext_start + ctext_length - ESP_TAIL_SIZE - self.esp_tail:new_from_mem(esp_tail_start, ESP_TAIL_SIZE) + local esp_trailer_start = ctext_start + ctext_length - ESP_TAIL_SIZE + local esp_trailer = ffi.cast(esp_trailer_ptr_t, esp_trailer_start) - local ptext_length = - ctext_length - self.esp_tail:pad_length() - ESP_TAIL_SIZE - return ctext_start, ptext_length + local ptext_length = ctext_length - esp_trailer.pad_length - ESP_TAIL_SIZE + return ctext_start, ptext_length, esp_trailer.next_header end -- Decapsulation in transport mode is performed as follows: @@ -240,18 +255,18 @@ end function decrypt:decapsulate_transport6 (p) if p.length - TRANSPORT6_PAYLOAD_OFFSET < self.MIN_SIZE then return nil end - self.ip:new_from_mem(p.data + ETHERNET_SIZE, IPV6_SIZE) + local ip = ffi.cast(ipv6_ptr_t, p.data + ETHERNET_SIZE) local payload = p.data + TRANSPORT6_PAYLOAD_OFFSET local payload_length = p.length - TRANSPORT6_PAYLOAD_OFFSET - local ptext_start, ptext_length = - self:decrypt_payload(payload, payload_length) + local ptext_start, ptext_length, next_header = + self:decrypt_payload(payload, payload_length, ip) if not ptext_start then return nil end - self.ip:next_header(self.esp_tail:next_header()) - self.ip:payload_length(ptext_length) + ip.next_header = next_header + ip.payload_length = htons(ptext_length) C.memmove(payload, ptext_start, ptext_length) p = packet.resize(p, TRANSPORT6_PAYLOAD_OFFSET + ptext_length) @@ -270,27 +285,28 @@ end function decrypt:decapsulate_tunnel (p) if p.length < self.MIN_SIZE then return nil end - local ptext_start, ptext_length = self:decrypt_payload(p.data, p.length) + local ptext_start, ptext_length, next_header = + self:decrypt_payload(p.data, p.length) if not ptext_start then return nil end p = packet.shiftleft(p, self.CTEXT_OFFSET) p = packet.resize(p, ptext_length) - return p, self.esp_tail:next_header() + return p, next_header end -function decrypt:audit (reason) +function decrypt:audit (reason, spi, seq, ip) if not self.auditing then return end - -- This is the information RFC4303 says we SHOULD log - logger:log("Rejecting packet (" .. - "SPI=" .. self.spi .. ", " .. - "src_addr='" .. self.ip:ntop(self.ip:src()) .. "', " .. - "dst_addr='" .. self.ip:ntop(self.ip:dst()) .. "', " .. - "seq_low=" .. self.esp:seq_no() .. ", " .. - "flow_id=" .. self.ip:flow_label() .. ", " .. - "reason='" .. reason .. "'" .. - ")") + -- The information RFC4303 says we SHOULD log: + logger:log(("Rejected packet (spi=%d, seq=%d, " + .."src_ip=%s, dst_ip=%s, flow_id=0x%x, " + .."reason=%q)") + :format(spi, seq, + ip and ipv6:ntop(ip.src_ip) or "unknown", + ip and ipv6:ntop(ip.dst_ip) or "unknown", + ip and ipv6_fl(ip) or 0, + reason)) end function decrypt:resync (ptr, length, seq_low, seq_high) @@ -331,7 +347,7 @@ function selftest () key = "00112233445566778899AABBCCDDEEFF", salt = "00112233", resync_threshold = 16, - resync_attempts = 8} + resync_attempts = 8 } local enc, dec = encrypt:new(conf), decrypt:new(conf) local payload = packet.from_string( [[abcdefghijklmnopqrstuvwxyz @@ -414,10 +430,12 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ enc.seq.no = 2^32 dec.seq.no = 2^32 + dec.window_size + 1 local px = op.encap(packet.clone(p)) + dec.auditing = true assert(not op.decap(px), "Accepted out of window Sequence Number.") assert(dec.seq:high() == 1 and dec.seq:low() == dec.window_size+1, "Corrupted Sequence Number.") + dec.auditing = false -- Test anti-replay: From a set of 15 packets, first send all those -- that have an even sequence number. Then, send all 15. Verify that -- in the 2nd run, packets with even sequence numbers are rejected while diff --git a/src/lib/protocol/esp.lua b/src/lib/protocol/esp.lua deleted file mode 100644 index 638a8b05f8..0000000000 --- a/src/lib/protocol/esp.lua +++ /dev/null @@ -1,50 +0,0 @@ -module(..., package.seeall) -local ffi = require("ffi") -local header = require("lib.protocol.header") -local lib = require("core.lib") -local ntohl, htonl = lib.ntohl, lib.htonl - -local esp = subClass(header) - --- Class variables -esp._name = "esp" -esp:init( - { - [1] = ffi.typeof[[ - struct { - uint32_t spi; - uint32_t seq_no; - } __attribute__((packed)) - ]] - }) - --- Class methods - -function esp:new (config) - local o = esp:superClass().new(self) - o:spi(config.spi) - o:seq_no(config.seq_no) - return o -end - --- Instance methods - -function esp:spi (spi) - local h = self:header() - if spi ~= nil then - h.spi = htonl(spi) - else - return(ntohl(h.spi)) - end -end - -function esp:seq_no (seq_no) - local h = self:header() - if seq_no ~= nil then - h.seq_no = htonl(seq_no) - else - return(ntohl(h.seq_no)) - end -end - -return esp diff --git a/src/lib/protocol/esp_tail.lua b/src/lib/protocol/esp_tail.lua deleted file mode 100644 index d8cadfee3a..0000000000 --- a/src/lib/protocol/esp_tail.lua +++ /dev/null @@ -1,48 +0,0 @@ -module(..., package.seeall) -local ffi = require("ffi") -local header = require("lib.protocol.header") - -local esp_tail = subClass(header) - --- Class variables -esp_tail._name = "esp_tail" -esp_tail:init( - { - [1] = ffi.typeof[[ - struct { - uint8_t pad_length; - uint8_t next_header; - } __attribute__((packed)) - ]] - }) - --- Class methods - -function esp_tail:new (config) - local o = esp_tail:superClass().new(self) - o:pad_length(config.pad_length) - o:next_header(config.next_header) - return o -end - --- Instance methods - -function esp_tail:pad_length (length) - local h = self:header() - if length ~= nil then - h.pad_length = length - else - return h.pad_length - end -end - -function esp_tail:next_header (next_header) - local h = self:header() - if next_header ~= nil then - h.next_header = next_header - else - return h.next_header - end -end - -return esp_tail From 43d498a26cc54cbed32bf61ea7a8a59611e818f4 Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Wed, 11 Apr 2018 17:51:54 +0200 Subject: [PATCH 08/11] lib.ipsec.esp: use full 16 (instead of 12) byte ICV Support the one mandatory ICV length, RFC4106 says: Implementations MUST support a full-length 16-octet ICV, and MAY support 8 or 12 octet ICVs, and MUST NOT support other ICV lengths. Also use the chance to use standard AEAD indentifers to denote the supported AEAD, as per ietf-ipsec@2018-01-08.yang schema. --- src/apps/ipsec/README.md | 5 +++-- src/apps/ipsec/esp.lua | 16 ++++++++-------- src/apps/ipsec/test-linux-compat.sh | 5 +++-- src/lib/ipsec/README.md | 10 +++++----- src/lib/ipsec/aes_128_gcm.lua | 6 ++++-- src/lib/ipsec/aes_128_gcm_avx.dasl | 12 ++++++------ src/lib/ipsec/esp.lua | 15 +++++++++------ src/program/lisper/lisper.lua | 4 ++-- src/program/snabbmark/snabbmark.lua | 2 +- 9 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/apps/ipsec/README.md b/src/apps/ipsec/README.md index 4233502e59..219c09e405 100644 --- a/src/apps/ipsec/README.md +++ b/src/apps/ipsec/README.md @@ -41,8 +41,9 @@ argument. The following keys are defined: — Key **aead** -*Optional*. The AEAD to use for encryption and authentication. For now, only -the default `"aes-gcm-128-12"` is supported. +*Optional*. The identifier of the AEAD to use for encryption and +authentication. For now, only the default `"aes-gcm-16-icv"` (AES-GCM with a 16 +octet ICV) is supported. — Key **spi** diff --git a/src/apps/ipsec/esp.lua b/src/apps/ipsec/esp.lua index a01787b974..5f4326f29a 100644 --- a/src/apps/ipsec/esp.lua +++ b/src/apps/ipsec/esp.lua @@ -1,7 +1,7 @@ -- Use of this source code is governed by the Apache 2.0 license; see COPYING. --- This app implements a point-to-point encryption tunnel using ESP with --- AES128GCM12 in transport mode over IPv6. +-- Apps that implements point-to-point ESP tunnels in transport and tunnel mode +-- for IPv6. module(..., package.seeall) local esp = require("lib.ipsec.esp") @@ -12,7 +12,7 @@ local ipv6 = require("lib.protocol.ipv6") Transport6 = { config = { spi = {required=true}, - aead = {default="aes-gcm-128-12"}, + aead = {default="aes-gcm-16-icv"}, transmit_key = {required=true}, transmit_salt = {required=true}, receive_key = {required=true}, @@ -32,12 +32,12 @@ function Transport6:new (conf) assert(conf.transmit_salt ~= conf.receive_salt, "Refusing to operate with transmit_salt == receive_salt") self.encrypt = esp.encrypt:new{ - mode = conf.aead, + aead = conf.aead, spi = conf.spi, key = conf.transmit_key, salt = conf.transmit_salt} self.decrypt = esp.decrypt:new{ - mode = conf.aead, + aead = conf.aead, spi = conf.spi, key = conf.receive_key, salt = conf.receive_salt, @@ -82,7 +82,7 @@ Tunnel6 = { self_ip = {required=true}, nexthop_ip = {required=true}, spi = {required=true}, - aead = {default="aes-gcm-128-12"}, + aead = {default="aes-gcm-16-icv"}, transmit_key = {required=true}, transmit_salt = {required=true}, receive_key = {required=true}, @@ -105,13 +105,13 @@ function Tunnel6:new (conf) assert(conf.selftest or conf.transmit_salt ~= conf.receive_salt, "Refusing to operate with transmit_salt == receive_salt") self.encrypt = esp.encrypt:new{ - mode = conf.aead, + aead = conf.aead, spi = conf.spi, key = conf.transmit_key, salt = conf.transmit_salt } self.decrypt = esp.decrypt:new{ - mode = conf.aead, + aead = conf.aead, spi = conf.spi, key = conf.receive_key, salt = conf.receive_salt, diff --git a/src/apps/ipsec/test-linux-compat.sh b/src/apps/ipsec/test-linux-compat.sh index b83f698469..5937f25cb0 100755 --- a/src/apps/ipsec/test-linux-compat.sh +++ b/src/apps/ipsec/test-linux-compat.sh @@ -51,8 +51,9 @@ ID_REV="$SDP_REV $SPISTR" REPLAY="replay-window 128" FLAG="flag esn" -RALGO="aead rfc4106\(gcm\(aes\)\) 0x$RKS 96" -TALGO="aead rfc4106\(gcm\(aes\)\) 0x$TKS 96" +# |aead |keymat |icv bits +RALGO="aead rfc4106\(gcm\(aes\)\) 0x$RKS 128" +TALGO="aead rfc4106\(gcm\(aes\)\) 0x$TKS 128" cmd="echo 'spdflush; flush;' | setkey -c" cmd="$cmd; ip xfrm state add $ID_FWD mode $MODE $REPLAY $FLAG $TALGO" diff --git a/src/lib/ipsec/README.md b/src/lib/ipsec/README.md index d4002fcb0e..93314dcccc 100644 --- a/src/lib/ipsec/README.md +++ b/src/lib/ipsec/README.md @@ -2,9 +2,9 @@ The `lib.ipsec.esp` module contains two classes `encrypt` and `decrypt` which implement packet encryption and decryption with IPsec ESP in both tunnel and -transport modes. Currently, the only supported cipher is AES-GCM cipher with -128‑bit keys, 4 bytes of salt, and a 12 byte authentication code. These classes -do not implement any key exchange protocol. +transport modes. Currently, the only supported cipher is AES-GCM with 128‑bit +keys, 4 bytes of salt, and a 16 byte authentication code. These classes do not +implement any key exchange protocol. References: @@ -20,8 +20,8 @@ References: Returns a new encryption/decryption context respectively. *Config* must a be a table with the following keys: -* `mode` - Encryption mode (string). The only accepted value is - `"aes-gcm-128-12"`. +* `aead` - AEAD identifier (string). The only accepted value is + `"aes-gcm-16-icv"` (AES-GCM with a 16 byte ICV). * `spi` - A 32 bit integer denoting the “Security Parameters Index” as specified in RFC 4303. * `key` - Hexadecimal string of 32 digits (two digits for each byte, most diff --git a/src/lib/ipsec/aes_128_gcm.lua b/src/lib/ipsec/aes_128_gcm.lua index 3d3362805f..186b9df50a 100644 --- a/src/lib/ipsec/aes_128_gcm.lua +++ b/src/lib/ipsec/aes_128_gcm.lua @@ -78,6 +78,7 @@ local aes_128_gcm = {} function aes_128_gcm:new (spi, key, salt) assert(spi, "Need SPI.") + -- We only support 128-bit keys. assert(key and #key == 32, "Need 16 bytes of key material.") assert(salt and #salt == 8, "Need 4 bytes of salt.") local o = {} @@ -85,7 +86,8 @@ function aes_128_gcm:new (spi, key, salt) ffi.copy(o.key, lib.hexundump(key, 16), 16) o.IV_SIZE = 8 o.iv = iv:new(lib.hexundump(salt, 4)) - o.AUTH_SIZE = 12 + -- “Implementations MUST support a full-length 16-octet ICV” + o.AUTH_SIZE = 16 o.auth_buf = ffi.new("uint8_t[?]", o.AUTH_SIZE) o.AAD_SIZE = 12 o.aad = aad:new(spi) @@ -118,7 +120,7 @@ function aes_128_gcm:decrypt (out_ptr, seq_low, seq_high, iv, ciphertext, length u8_ptr(self.iv:header_ptr()), u8_ptr(self.aad:header_ptr()), self.AAD_SIZE, self.auth_buf, self.AUTH_SIZE) - return ASM.auth12_equal(self.auth_buf, ciphertext + length) == 0 + return ASM.auth16_equal(self.auth_buf, ciphertext + length) == 0 end diff --git a/src/lib/ipsec/aes_128_gcm_avx.dasl b/src/lib/ipsec/aes_128_gcm_avx.dasl index b4cae2b353..3087b58d83 100644 --- a/src/lib/ipsec/aes_128_gcm_avx.dasl +++ b/src/lib/ipsec/aes_128_gcm_avx.dasl @@ -451,11 +451,11 @@ local function keyexp(Dst) | ret end -local function auth12_equal(Dst) +local function auth16_equal(Dst) | mov rax, [arg1] - | mov edx, [arg1 + 8] + | mov rdx, [arg1 + 8] | xor rax, [arg2] - | xor edx, [arg2 + 8] + | xor rdx, [arg2 + 8] | or rax, rdx | ret end @@ -482,8 +482,8 @@ local function generator(Dst) | vmovdqu [arg2], xmm0 | ret |.align 16 - |->auth12_equal: - || auth12_equal(Dst) + |->auth16_equal: + || auth16_equal(Dst) -- Data |.align 64 @@ -514,5 +514,5 @@ return setmetatable({ aesni_gcm_enc_avx_gen4 = ffi.cast(fn_t, entry.aesni_gcm_enc_avx_gen4), aesni_gcm_dec_avx_gen4 = ffi.cast(fn_t, entry.aesni_gcm_dec_avx_gen4), aesni_encrypt_single_block = ffi.cast("void(*)(gcm_data*, uint8_t*)", entry.aesni_encrypt_single_block), - auth12_equal = ffi.cast("uint64_t(*)(uint8_t[12], uint8_t[12])", entry.auth12_equal) + auth16_equal = ffi.cast("uint64_t(*)(uint8_t[16], uint8_t[16])", entry.auth16_equal) }, {_anchor = mcode}) diff --git a/src/lib/ipsec/esp.lua b/src/lib/ipsec/esp.lua index e48659c561..e744681a59 100644 --- a/src/lib/ipsec/esp.lua +++ b/src/lib/ipsec/esp.lua @@ -1,7 +1,7 @@ --- Implementation of IPsec ESP using AES-128-GCM with a 12 byte ICV and --- “Extended Sequence Number” (see RFC 4303 and RFC 4106). Provides --- address-family independent encapsulation/decapsulation routines for --- “tunnel mode” and “transport mode” routines for IPv6. +-- Implementation of IPsec ESP using AES-GCM with 128-bit keys, 16 byte ICV and +-- “Extended Sequence Numbers” (see RFC 4303 and RFC 4106). Provides +-- address-family independent encapsulation/decapsulation routines for “tunnel +-- mode” and “transport mode” routines for IPv6. -- -- Notes: -- @@ -45,8 +45,11 @@ local TRANSPORT6_PAYLOAD_OFFSET = ETHERNET_SIZE + IPV6_SIZE local function padding (a, l) return (a - l%a) % a end +-- AEAD identifier from: +-- https://github.com/YangModels/yang/blob/master/experimental/ietf-extracted-YANG-modules/ietf-ipsec@2018-01-08.yang + function esp_new (conf) - assert(conf.mode == "aes-gcm-128-12", "Only supports 'aes-gcm-128-12'.") + assert(conf.aead == "aes-gcm-16-icv", "Only supports aes-gcm-16-icv") assert(conf.spi, "Need SPI.") local o = { @@ -327,7 +330,7 @@ end function selftest () local conf = { spi = 0x0, - mode = "aes-gcm-128-12", + aead = "aes-gcm-16-icv", key = "00112233445566778899AABBCCDDEEFF", salt = "00112233", resync_threshold = 16, diff --git a/src/program/lisper/lisper.lua b/src/program/lisper/lisper.lua index cf6797b6ea..d9d647dd3e 100644 --- a/src/program/lisper/lisper.lua +++ b/src/program/lisper/lisper.lua @@ -255,7 +255,7 @@ local function update_fib(s) if false and key_id and encap_key and decap_key then local enc = esp.encrypt:new{ spi = key_id, - mode = "aes-gcm-128-12", + aead = "aes-gcm-16-icv", keymat = encap_key, salt = conf.esp_salt, } @@ -264,7 +264,7 @@ local function update_fib(s) end local dec = esp.decrypt:new{ spi = key_id, - mode = "aes-gcm-128-12", + aead = "aes-gcm-16-icv", keymat = decap_key, salt = conf.esp_salt, } diff --git a/src/program/snabbmark/snabbmark.lua b/src/program/snabbmark/snabbmark.lua index 5432b907b0..cb0a1a045a 100644 --- a/src/program/snabbmark/snabbmark.lua +++ b/src/program/snabbmark/snabbmark.lua @@ -365,7 +365,7 @@ function esp (npackets, packet_size, mode, direction, profile) end local plain = d:packet() local conf = { spi = 0x0, - mode = "aes-gcm-128-12", + aead = "aes-gcm-16-icv", key = "00112233445566778899AABBCCDDEEFF", salt = "00112233"} local enc, dec = esp.encrypt:new(conf), esp.decrypt:new(conf) From 66a0dbb7059063f16e4e3d402065a548329f9525 Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Fri, 1 Jun 2018 17:39:55 +0200 Subject: [PATCH 09/11] lib.ipsec.esp: keep lib.protocol.esp* --- src/lib/ipsec/esp.lua | 23 +++++----------- src/lib/protocol/esp.lua | 50 +++++++++++++++++++++++++++++++++++ src/lib/protocol/esp_tail.lua | 48 +++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 17 deletions(-) create mode 100644 src/lib/protocol/esp.lua create mode 100644 src/lib/protocol/esp_tail.lua diff --git a/src/lib/ipsec/esp.lua b/src/lib/ipsec/esp.lua index 853b8a24f3..cb44283b52 100644 --- a/src/lib/ipsec/esp.lua +++ b/src/lib/ipsec/esp.lua @@ -22,6 +22,8 @@ local header = require("lib.protocol.header") local datagram = require("lib.protocol.datagram") local ethernet = require("lib.protocol.ethernet") local ipv6 = require("lib.protocol.ipv6") +local esp = require("lib.protocol.esp") +local esp_tail = require("lib.protocol.esp_tail") local aes_128_gcm = require("lib.ipsec.aes_128_gcm") local seq_no_t = require("lib.ipsec.seq_no_t") local lib = require("core.lib") @@ -39,26 +41,13 @@ PROTOCOL = 50 -- https://tools.ietf.org/html/rfc4303#section-2 local ipv6_ptr_t = ffi.typeof("$ *", ipv6:ctype()) local function ipv6_fl (ip) return bit.lshift(ntohl(ip.v_tc_fl), 12) end -local esp_header_t = ffi.typeof( - [[struct { - uint32_t spi; - uint32_t seq_no; - } __attribute__((packed))]] -) -local esp_header_ptr_t = ffi.typeof("$ *", esp_header_t) - -local esp_trailer_t = ffi.typeof( - [[struct { - uint8_t pad_length; - uint8_t next_header; - } __attribute__((packed))]] -) -local esp_trailer_ptr_t = ffi.typeof("$ *", esp_trailer_t) +local esp_header_ptr_t = ffi.typeof("$ *", esp:ctype()) +local esp_trailer_ptr_t = ffi.typeof("$ *", esp_tail:ctype()) local ETHERNET_SIZE = ethernet:sizeof() local IPV6_SIZE = ipv6:sizeof() -local ESP_SIZE = ffi.sizeof(esp_header_t) -local ESP_TAIL_SIZE = ffi.sizeof(esp_trailer_t) +local ESP_SIZE = esp:sizeof() +local ESP_TAIL_SIZE = esp_tail:sizeof() local TRANSPORT6_PAYLOAD_OFFSET = ETHERNET_SIZE + IPV6_SIZE diff --git a/src/lib/protocol/esp.lua b/src/lib/protocol/esp.lua new file mode 100644 index 0000000000..638a8b05f8 --- /dev/null +++ b/src/lib/protocol/esp.lua @@ -0,0 +1,50 @@ +module(..., package.seeall) +local ffi = require("ffi") +local header = require("lib.protocol.header") +local lib = require("core.lib") +local ntohl, htonl = lib.ntohl, lib.htonl + +local esp = subClass(header) + +-- Class variables +esp._name = "esp" +esp:init( + { + [1] = ffi.typeof[[ + struct { + uint32_t spi; + uint32_t seq_no; + } __attribute__((packed)) + ]] + }) + +-- Class methods + +function esp:new (config) + local o = esp:superClass().new(self) + o:spi(config.spi) + o:seq_no(config.seq_no) + return o +end + +-- Instance methods + +function esp:spi (spi) + local h = self:header() + if spi ~= nil then + h.spi = htonl(spi) + else + return(ntohl(h.spi)) + end +end + +function esp:seq_no (seq_no) + local h = self:header() + if seq_no ~= nil then + h.seq_no = htonl(seq_no) + else + return(ntohl(h.seq_no)) + end +end + +return esp diff --git a/src/lib/protocol/esp_tail.lua b/src/lib/protocol/esp_tail.lua new file mode 100644 index 0000000000..d8cadfee3a --- /dev/null +++ b/src/lib/protocol/esp_tail.lua @@ -0,0 +1,48 @@ +module(..., package.seeall) +local ffi = require("ffi") +local header = require("lib.protocol.header") + +local esp_tail = subClass(header) + +-- Class variables +esp_tail._name = "esp_tail" +esp_tail:init( + { + [1] = ffi.typeof[[ + struct { + uint8_t pad_length; + uint8_t next_header; + } __attribute__((packed)) + ]] + }) + +-- Class methods + +function esp_tail:new (config) + local o = esp_tail:superClass().new(self) + o:pad_length(config.pad_length) + o:next_header(config.next_header) + return o +end + +-- Instance methods + +function esp_tail:pad_length (length) + local h = self:header() + if length ~= nil then + h.pad_length = length + else + return h.pad_length + end +end + +function esp_tail:next_header (next_header) + local h = self:header() + if next_header ~= nil then + h.next_header = next_header + else + return h.next_header + end +end + +return esp_tail From 796c177a6d4cd08b0e05debdf89f5be8ee505d4d Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Tue, 12 Jun 2018 13:45:11 +0200 Subject: [PATCH 10/11] lib.ipsec.esp: optimize padding by specializing for power of two Saves some cycles during encapsulation by specializing the padding function for power of two alignments. --- src/lib/ipsec/esp.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/ipsec/esp.lua b/src/lib/ipsec/esp.lua index cb44283b52..5e4d0cf487 100644 --- a/src/lib/ipsec/esp.lua +++ b/src/lib/ipsec/esp.lua @@ -30,6 +30,7 @@ local lib = require("core.lib") local ffi = require("ffi") local C = ffi.C local logger = lib.logger_new({ rate = 32, module = 'esp' }) +local band = bit.band local htons, htonl, ntohl = lib.htons, lib.htonl, lib.ntohl @@ -51,7 +52,8 @@ local ESP_TAIL_SIZE = esp_tail:sizeof() local TRANSPORT6_PAYLOAD_OFFSET = ETHERNET_SIZE + IPV6_SIZE -local function padding (a, l) return (a - l%a) % a end +-- NB: `a' must be a power of two +local function padding (a, l) return bit.band(-l, a-1) end -- AEAD identifier from: -- https://github.com/YangModels/yang/blob/master/experimental/ietf-extracted-YANG-modules/ietf-ipsec@2018-01-08.yang From 5b86f940980cef9e94b08984da15074ed2b59c7b Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Mon, 10 Sep 2018 19:55:04 +0200 Subject: [PATCH 11/11] lib.ipsec.esp: fix a packet leak in :resync() --- src/lib/ipsec/esp.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/ipsec/esp.lua b/src/lib/ipsec/esp.lua index 5e4d0cf487..7a55596049 100644 --- a/src/lib/ipsec/esp.lua +++ b/src/lib/ipsec/esp.lua @@ -194,6 +194,8 @@ function decrypt:new (conf) o.auditing = conf.auditing + o.copy = packet.allocate() + return setmetatable(o, {__index=decrypt}) end @@ -320,13 +322,12 @@ function decrypt:resync (ptr, length, seq_low, seq_high) ) end - local p_orig = packet.from_pointer(ptr, length) + local p_orig = packet.append(packet.resize(self.copy, 0), ptr, length) for i = 1, self.resync_attempts do seq_high = seq_high + 1 if self.cipher:decrypt( ctext_start, seq_low, seq_high, iv_start, ctext_start, ctext_length ) then - packet.free(p_orig) return seq_high else ffi.copy(ptr, p_orig.data, length)