Skip to content

Commit

Permalink
Extended Sequence Numbers support in ESP
Browse files Browse the repository at this point in the history
  • Loading branch information
phuhavan authored and gpotter2 committed Feb 5, 2024
1 parent 90ec725 commit ca5a069
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 13 deletions.
34 changes: 21 additions & 13 deletions scapy/layers/ipsec.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,16 +674,17 @@ def sign(self, pkt, key, esn_en=False, esn=0):
mac = self.new_mac(key)

if pkt.haslayer(ESP):
mac.update(raw(pkt[ESP]))
mac.update(bytes(pkt[ESP]))
if esn_en:
# RFC4303 sect 2.2.1
mac.update(struct.pack('!L', esn))
pkt[ESP].data += mac.finalize()[:self.icv_size]

elif pkt.haslayer(AH):
clone = zero_mutable_fields(pkt.copy(), sending=True)
mac.update(bytes(zero_mutable_fields(pkt.copy(), sending=True)))
if esn_en:
temp = raw(clone) + struct.pack('!L', esn)
else:
temp = raw(clone)
mac.update(temp)
# RFC4302 sect 2.5.1
mac.update(struct.pack('!L', esn))
pkt[AH].icv = mac.finalize()[:self.icv_size]

return pkt
Expand Down Expand Up @@ -712,7 +713,10 @@ def verify(self, pkt, key, esn_en=False, esn=0):
pkt_icv = pkt.data[len(pkt.data) - self.icv_size:]
clone = pkt.copy()
clone.data = clone.data[:len(clone.data) - self.icv_size]
temp = raw(clone)
mac.update(bytes(clone))
if esn_en:
# RFC4303 sect 2.2.1
mac.update(struct.pack('!L', esn))

elif pkt.haslayer(AH):
if len(pkt[AH].icv) != self.icv_size:
Expand All @@ -721,12 +725,11 @@ def verify(self, pkt, key, esn_en=False, esn=0):
pkt[AH].icv = pkt[AH].icv[:self.icv_size]
pkt_icv = pkt[AH].icv
clone = zero_mutable_fields(pkt.copy(), sending=False)
mac.update(bytes(clone))
if esn_en:
temp = raw(clone) + struct.pack('!L', esn)
else:
temp = raw(clone)
# RFC4302 sect 2.5.1
mac.update(struct.pack('!L', esn))

mac.update(temp)
computed_icv = mac.finalize()[:self.icv_size]

# XXX: Cannot use mac.verify because the ICV can be truncated
Expand Down Expand Up @@ -1033,7 +1036,10 @@ def _encrypt_esp(self, pkt, seq_num=None, iv=None, esn_en=None, esn=None):
esn_en=esn_en or self.esn_en,
esn=esn or self.esn)

self.auth_algo.sign(esp, self.auth_key)
self.auth_algo.sign(esp,
self.auth_key,
esn_en=esn_en or self.esn_en,
esn=esn or self.esn)

if self.nat_t_header:
nat_t_header = self.nat_t_header.copy()
Expand Down Expand Up @@ -1144,7 +1150,9 @@ def _decrypt_esp(self, pkt, verify=True, esn_en=None, esn=None):

if verify:
self.check_spi(pkt)
self.auth_algo.verify(encrypted, self.auth_key)
self.auth_algo.verify(encrypted, self.auth_key,
esn_en=esn_en or self.esn_en,
esn=esn or self.esn)

esp = self.crypt_algo.decrypt(self, encrypted, self.crypt_key,
self.crypt_icv_size or
Expand Down
25 changes: 25 additions & 0 deletions test/scapy/layers/ipsec.uts
Original file line number Diff line number Diff line change
Expand Up @@ -1506,6 +1506,31 @@ try:
except IPSecIntegrityError as err:
err

#######################################
= IPv4 / ESP - Transport - AES-CBC - HMAC-SHA2-256-128 -- ESN

p = IP(src='1.1.1.1', dst='2.2.2.2')
p /= TCP(sport=45012, dport=80)
p /= Raw('hello world')
p = IP(raw(p))
p

enc_key = bytes.fromhex("85ee354b4675a9c5d16e3d6f4118043b")
auth_key = bytes.fromhex("6f79bf94da7dde3c86009934d9258f1b3fc2f5382aca9c9cb8e216eed235f34c")

sa = SecurityAssociation(ESP, spi=0xcf54ccdf, crypt_algo='AES-CBC',
crypt_key=enc_key,
auth_algo='SHA2-256-128', auth_key=auth_key,
esn_en=True, esn=68)
e = sa.encrypt(p, iv=bytes.fromhex("11223344112233441122334411223344"))


assert bytes(e) == bytes.fromhex("4500006c000100004032745a0101010102020202cf54ccdf0000000111223344112233441122334411223344f5bda519c9ae64f283f0fc18a8d253eca8b34c2120c8958a97ec9d8e67756da2523fce9b5541c57fddf090afc2bfd97e8703203953f853eb61482e4c1384d4c8")

* integrity verification should pass
d = sa.decrypt(e)
d

#######################################
= IPv4 / ESP - Transport - AES-GCM - NULL

Expand Down

0 comments on commit ca5a069

Please sign in to comment.