Advertisement
Sweetening

Untitled

Sep 27th, 2024
20
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 43.91 KB | None | 0 0
  1. #############################################################################
  2. # ipsec.py --- IPsec support for Scapy #
  3. # #
  4. # Copyright (C) 2014 6WIND #
  5. # #
  6. # This program is free software; you can redistribute it and/or modify it #
  7. # under the terms of the GNU General Public License version 2 as #
  8. # published by the Free Software Foundation. #
  9. # #
  10. # This program is distributed in the hope that it will be useful, but #
  11. # WITHOUT ANY WARRANTY; without even the implied warranty of #
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
  13. # General Public License for more details. #
  14. #############################################################################
  15. r"""
  16. IPsec layer
  17. ===========
  18.  
  19. Example of use:
  20.  
  21. >>> sa = SecurityAssociation(ESP, spi=0xdeadbeef, crypt_algo='AES-CBC',
  22. ... crypt_key='sixteenbytes key')
  23. >>> p = IP(src='1.1.1.1', dst='2.2.2.2')
  24. >>> p /= TCP(sport=45012, dport=80)
  25. >>> p /= Raw('testdata')
  26. >>> p = IP(raw(p))
  27. >>> p
  28. <IP version=4L ihl=5L tos=0x0 len=48 id=1 flags= frag=0L ttl=64 proto=tcp chksum=0x74c2 src=1.1.1.1 dst=2.2.2.2 options=[] |<TCP sport=45012 dport=http seq=0 ack=0 dataofs=5L reserved=0L flags=S window=8192 chksum=0x1914 urgptr=0 options=[] |<Raw load='testdata' |>>> # noqa: E501
  29. >>>
  30. >>> e = sa.encrypt(p)
  31. >>> e
  32. <IP version=4L ihl=5L tos=0x0 len=76 id=1 flags= frag=0L ttl=64 proto=esp chksum=0x747a src=1.1.1.1 dst=2.2.2.2 |<ESP spi=0xdeadbeef seq=1 data=b'\xf8\xdb\x1e\x83[T\xab\\\xd2\x1b\xed\xd1\xe5\xc8Y\xc2\xa5d\x92\xc1\x05\x17\xa6\x92\x831\xe6\xc1]\x9a\xd6K}W\x8bFfd\xa5B*+\xde\xc8\x89\xbf{\xa9' |>> # noqa: E501
  33. >>>
  34. >>> d = sa.decrypt(e)
  35. >>> d
  36. <IP version=4L ihl=5L tos=0x0 len=48 id=1 flags= frag=0L ttl=64 proto=tcp chksum=0x74c2 src=1.1.1.1 dst=2.2.2.2 |<TCP sport=45012 dport=http seq=0 ack=0 dataofs=5L reserved=0L flags=S window=8192 chksum=0x1914 urgptr=0 options=[] |<Raw load='testdata' |>>> # noqa: E501
  37. >>>
  38. >>> d == p
  39. True
  40. """
  41.  
  42. from __future__ import absolute_import
  43. try:
  44. from math import gcd
  45. except ImportError:
  46. from fractions import gcd
  47. import os
  48. import socket
  49. import struct
  50.  
  51. from scapy.config import conf, crypto_validator
  52. from scapy.compat import orb, raw
  53. from scapy.data import IP_PROTOS
  54. from scapy.error import log_loading
  55. from scapy.fields import ByteEnumField, ByteField, IntField, PacketField, \
  56. ShortField, StrField, XIntField, XStrField, XStrLenField
  57. from scapy.packet import Packet, bind_layers, Raw
  58. from scapy.layers.inet import IP, UDP
  59. import scapy.modules.six as six
  60. from scapy.modules.six.moves import range
  61. from scapy.layers.inet6 import IPv6, IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt, \
  62. IPv6ExtHdrRouting
  63.  
  64.  
  65. ###############################################################################
  66. class AH(Packet):
  67. """
  68. Authentication Header
  69.  
  70. See https://tools.ietf.org/rfc/rfc4302.txt
  71. """
  72.  
  73. name = 'AH'
  74.  
  75. def __get_icv_len(self):
  76. """
  77. Compute the size of the ICV based on the payloadlen field.
  78. Padding size is included as it can only be known from the authentication # noqa: E501
  79. algorithm provided by the Security Association.
  80. """
  81. # payloadlen = length of AH in 32-bit words (4-byte units), minus "2"
  82. # payloadlen = 3 32-bit word fixed fields + ICV + padding - 2
  83. # ICV = (payloadlen + 2 - 3 - padding) in 32-bit words
  84. return (self.payloadlen - 1) * 4
  85.  
  86. fields_desc = [
  87. ByteEnumField('nh', None, IP_PROTOS),
  88. ByteField('payloadlen', None),
  89. ShortField('reserved', None),
  90. XIntField('spi', 0x0),
  91. IntField('seq', 0),
  92. XStrLenField('icv', None, length_from=__get_icv_len),
  93. # Padding len can only be known with the SecurityAssociation.auth_algo
  94. XStrLenField('padding', None, length_from=lambda x: 0),
  95. ]
  96.  
  97. overload_fields = {
  98. IP: {'proto': socket.IPPROTO_AH},
  99. IPv6: {'nh': socket.IPPROTO_AH},
  100. IPv6ExtHdrHopByHop: {'nh': socket.IPPROTO_AH},
  101. IPv6ExtHdrDestOpt: {'nh': socket.IPPROTO_AH},
  102. IPv6ExtHdrRouting: {'nh': socket.IPPROTO_AH},
  103. }
  104.  
  105.  
  106. bind_layers(IP, AH, proto=socket.IPPROTO_AH)
  107. bind_layers(IPv6, AH, nh=socket.IPPROTO_AH)
  108. bind_layers(AH, IP, nh=socket.IPPROTO_IP)
  109. bind_layers(AH, IPv6, nh=socket.IPPROTO_IPV6)
  110.  
  111. ###############################################################################
  112.  
  113.  
  114. class ESP(Packet):
  115. """
  116. Encapsulated Security Payload
  117.  
  118. See https://tools.ietf.org/rfc/rfc4303.txt
  119. """
  120. name = 'ESP'
  121.  
  122. fields_desc = [
  123. XIntField('spi', 0x0),
  124. IntField('seq', 0),
  125. XStrField('data', None),
  126. ]
  127.  
  128. overload_fields = {
  129. IP: {'proto': socket.IPPROTO_ESP},
  130. IPv6: {'nh': socket.IPPROTO_ESP},
  131. IPv6ExtHdrHopByHop: {'nh': socket.IPPROTO_ESP},
  132. IPv6ExtHdrDestOpt: {'nh': socket.IPPROTO_ESP},
  133. IPv6ExtHdrRouting: {'nh': socket.IPPROTO_ESP},
  134. }
  135.  
  136.  
  137. bind_layers(IP, ESP, proto=socket.IPPROTO_ESP)
  138. bind_layers(IPv6, ESP, nh=socket.IPPROTO_ESP)
  139. bind_layers(UDP, ESP, dport=4500) # NAT-Traversal encapsulation
  140. bind_layers(UDP, ESP, sport=4500) # NAT-Traversal encapsulation
  141.  
  142. ###############################################################################
  143.  
  144.  
  145. class _ESPPlain(Packet):
  146. """
  147. Internal class to represent unencrypted ESP packets.
  148. """
  149. name = 'ESP'
  150.  
  151. fields_desc = [
  152. XIntField('spi', 0x0),
  153. IntField('seq', 0),
  154.  
  155. StrField('iv', ''),
  156. PacketField('data', '', Raw),
  157. StrField('padding', ''),
  158.  
  159. ByteField('padlen', 0),
  160. ByteEnumField('nh', 0, IP_PROTOS),
  161. StrField('icv', ''),
  162. ]
  163.  
  164. def data_for_encryption(self):
  165. return raw(self.data) + self.padding + struct.pack("BB", self.padlen, self.nh) # noqa: E501
  166.  
  167.  
  168. ###############################################################################
  169. if conf.crypto_valid:
  170. from cryptography.exceptions import InvalidTag
  171. from cryptography.hazmat.backends import default_backend
  172. from cryptography.hazmat.primitives.ciphers import (
  173. Cipher,
  174. algorithms,
  175. modes,
  176. )
  177. else:
  178. log_loading.info("Can't import python-cryptography v1.7+. "
  179. "Disabled IPsec encryption/authentication.")
  180. default_backend = None
  181. InvalidTag = Exception
  182. Cipher = algorithms = modes = None
  183.  
  184. ###############################################################################
  185.  
  186.  
  187. def _lcm(a, b):
  188. """
  189. Least Common Multiple between 2 integers.
  190. """
  191. if a == 0 or b == 0:
  192. return 0
  193. else:
  194. return abs(a * b) // gcd(a, b)
  195.  
  196.  
  197. class CryptAlgo(object):
  198. """
  199. IPsec encryption algorithm
  200. """
  201.  
  202. def __init__(self, name, cipher, mode, block_size=None, iv_size=None,
  203. key_size=None, icv_size=None, salt_size=None, format_mode_iv=None): # noqa: E501
  204. """
  205. :param name: the name of this encryption algorithm
  206. :param cipher: a Cipher module
  207. :param mode: the mode used with the cipher module
  208. :param block_size: the length a block for this algo. Defaults to the
  209. `block_size` of the cipher.
  210. :param iv_size: the length of the initialization vector of this algo.
  211. Defaults to the `block_size` of the cipher.
  212. :param key_size: an integer or list/tuple of integers. If specified,
  213. force the secret keys length to one of the values.
  214. Defaults to the `key_size` of the cipher.
  215. :param icv_size: the length of the Integrity Check Value of this algo.
  216. Used by Combined Mode Algorithms e.g. GCM
  217. :param salt_size: the length of the salt to use as the IV prefix.
  218. Usually used by Counter modes e.g. CTR
  219. :param format_mode_iv: function to format the Initialization Vector
  220. e.g. handle the salt value
  221. Default is the random buffer from `generate_iv`
  222. """
  223. self.name = name
  224. self.cipher = cipher
  225. self.mode = mode
  226. self.icv_size = icv_size
  227.  
  228. if modes and self.mode is not None:
  229. self.is_aead = issubclass(self.mode,
  230. modes.ModeWithAuthenticationTag)
  231. else:
  232. self.is_aead = False
  233.  
  234. if block_size is not None:
  235. self.block_size = block_size
  236. elif cipher is not None:
  237. self.block_size = cipher.block_size // 8
  238. else:
  239. self.block_size = 1
  240.  
  241. if iv_size is None:
  242. self.iv_size = self.block_size
  243. else:
  244. self.iv_size = iv_size
  245.  
  246. if key_size is not None:
  247. self.key_size = key_size
  248. elif cipher is not None:
  249. self.key_size = tuple(i // 8 for i in cipher.key_sizes)
  250. else:
  251. self.key_size = None
  252.  
  253. if salt_size is None:
  254. self.salt_size = 0
  255. else:
  256. self.salt_size = salt_size
  257.  
  258. if format_mode_iv is None:
  259. self._format_mode_iv = lambda iv, **kw: iv
  260. else:
  261. self._format_mode_iv = format_mode_iv
  262.  
  263. def check_key(self, key):
  264. """
  265. Check that the key length is valid.
  266.  
  267. :param key: a byte string
  268. """
  269. if self.key_size and not (len(key) == self.key_size or len(key) in self.key_size): # noqa: E501
  270. raise TypeError('invalid key size %s, must be %s' %
  271. (len(key), self.key_size))
  272.  
  273. def generate_iv(self):
  274. """
  275. Generate a random initialization vector.
  276. """
  277. # XXX: Handle counter modes with real counters? RFCs allow the use of
  278. # XXX: random bytes for counters, so it is not wrong to do it that way
  279. return os.urandom(self.iv_size)
  280.  
  281. @crypto_validator
  282. def new_cipher(self, key, mode_iv, digest=None):
  283. """
  284. :param key: the secret key, a byte string
  285. :param mode_iv: the initialization vector or nonce, a byte string.
  286. Formatted by `format_mode_iv`.
  287. :param digest: also known as tag or icv. A byte string containing the
  288. digest of the encrypted data. Only use this during
  289. decryption!
  290.  
  291. :returns: an initialized cipher object for this algo
  292. """
  293. if self.is_aead and digest is not None:
  294. # With AEAD, the mode needs the digest during decryption.
  295. return Cipher(
  296. self.cipher(key),
  297. self.mode(mode_iv, digest, len(digest)),
  298. default_backend(),
  299. )
  300. else:
  301. return Cipher(
  302. self.cipher(key),
  303. self.mode(mode_iv),
  304. default_backend(),
  305. )
  306.  
  307. def pad(self, esp):
  308. """
  309. Add the correct amount of padding so that the data to encrypt is
  310. exactly a multiple of the algorithm's block size.
  311.  
  312. Also, make sure that the total ESP packet length is a multiple of 4
  313. bytes.
  314.  
  315. :param esp: an unencrypted _ESPPlain packet
  316.  
  317. :returns: an unencrypted _ESPPlain packet with valid padding
  318. """
  319. # 2 extra bytes for padlen and nh
  320. data_len = len(esp.data) + 2
  321.  
  322. # according to the RFC4303, section 2.4. Padding (for Encryption)
  323. # the size of the ESP payload must be a multiple of 32 bits
  324. align = _lcm(self.block_size, 4)
  325.  
  326. # pad for block size
  327. esp.padlen = -data_len % align
  328.  
  329. # Still according to the RFC, the default value for padding *MUST* be an # noqa: E501
  330. # array of bytes starting from 1 to padlen
  331. # TODO: Handle padding function according to the encryption algo
  332. esp.padding = struct.pack("B" * esp.padlen, *range(1, esp.padlen + 1))
  333.  
  334. # If the following test fails, it means that this algo does not comply
  335. # with the RFC
  336. payload_len = len(esp.iv) + len(esp.data) + len(esp.padding) + 2
  337. if payload_len % 4 != 0:
  338. raise ValueError('The size of the ESP data is not aligned to 32 bits after padding.') # noqa: E501
  339.  
  340. return esp
  341.  
  342. def encrypt(self, sa, esp, key, esn_en=False, esn=0):
  343. """
  344. Encrypt an ESP packet
  345.  
  346. :param sa: the SecurityAssociation associated with the ESP packet.
  347. :param esp: an unencrypted _ESPPlain packet with valid padding
  348. :param key: the secret key used for encryption
  349. :esn_en: extended sequence number enable which allows to use 64-bit
  350. sequence number instead of 32-bit when using an AEAD
  351. algorithm
  352. :esn: extended sequence number (32 MSB)
  353. :return: a valid ESP packet encrypted with this algorithm
  354. """
  355. data = esp.data_for_encryption()
  356.  
  357. if self.cipher:
  358. mode_iv = self._format_mode_iv(algo=self, sa=sa, iv=esp.iv)
  359. cipher = self.new_cipher(key, mode_iv)
  360. encryptor = cipher.encryptor()
  361.  
  362. if self.is_aead:
  363. if esn_en:
  364. aad = struct.pack('!LLL', esp.spi, esn, esp.seq)
  365. else:
  366. aad = struct.pack('!LL', esp.spi, esp.seq)
  367. encryptor.authenticate_additional_data(aad)
  368. data = encryptor.update(data) + encryptor.finalize()
  369. data += encryptor.tag[:self.icv_size]
  370. else:
  371. data = encryptor.update(data) + encryptor.finalize()
  372.  
  373. return ESP(spi=esp.spi, seq=esp.seq, data=esp.iv + data)
  374.  
  375. def decrypt(self, sa, esp, key, icv_size=None, esn_en=False, esn=0):
  376. """
  377. Decrypt an ESP packet
  378.  
  379. :param sa: the SecurityAssociation associated with the ESP packet.
  380. :param esp: an encrypted ESP packet
  381. :param key: the secret key used for encryption
  382. :param icv_size: the length of the icv used for integrity check
  383. :param esn_en: extended sequence number enable which allows to use
  384. 64-bit sequence number instead of 32-bit when using an
  385. AEAD algorithm
  386. :param esn: extended sequence number (32 MSB)
  387. :returns: a valid ESP packet encrypted with this algorithm
  388. :raise scapy.layers.ipsec.IPSecIntegrityError: if the integrity check
  389. fails with an AEAD algorithm
  390. """
  391. if icv_size is None:
  392. icv_size = self.icv_size if self.is_aead else 0
  393.  
  394. iv = esp.data[:self.iv_size]
  395. data = esp.data[self.iv_size:len(esp.data) - icv_size]
  396. icv = esp.data[len(esp.data) - icv_size:]
  397.  
  398. if self.cipher:
  399. mode_iv = self._format_mode_iv(sa=sa, iv=iv)
  400. cipher = self.new_cipher(key, mode_iv, icv)
  401. decryptor = cipher.decryptor()
  402.  
  403. if self.is_aead:
  404. # Tag value check is done during the finalize method
  405. if esn_en:
  406. decryptor.authenticate_additional_data(
  407. struct.pack('!LLL', esp.spi, esn, esp.seq))
  408. else:
  409. decryptor.authenticate_additional_data(
  410. struct.pack('!LL', esp.spi, esp.seq))
  411. try:
  412. data = decryptor.update(data) + decryptor.finalize()
  413. except InvalidTag as err:
  414. raise IPSecIntegrityError(err)
  415.  
  416. # extract padlen and nh
  417. padlen = orb(data[-2])
  418. nh = orb(data[-1])
  419.  
  420. # then use padlen to determine data and padding
  421. data = data[:len(data) - padlen - 2]
  422. padding = data[len(data) - padlen - 2: len(data) - 2]
  423.  
  424. return _ESPPlain(spi=esp.spi,
  425. seq=esp.seq,
  426. iv=iv,
  427. data=data,
  428. padding=padding,
  429. padlen=padlen,
  430. nh=nh,
  431. icv=icv)
  432. ###############################################################################
  433. from cryptography.hazmat.decrepit.ciphers.algorithms import TripleDES # Updated import
  434. from cryptography.hazmat.primitives.ciphers import algorithms, modes # Ensure these imports are present
  435.  
  436. # The names of the encryption algorithms are the same than in scapy.contrib.ikev2 # noqa: E501
  437. # see http://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml
  438.  
  439. CRYPT_ALGOS = {
  440. 'NULL': CryptAlgo('NULL', cipher=None, mode=None, iv_size=0),
  441. }
  442.  
  443. if algorithms:
  444. CRYPT_ALGOS['AES-CBC'] = CryptAlgo('AES-CBC',
  445. cipher=algorithms.AES,
  446. mode=modes.CBC)
  447. _aes_ctr_format_mode_iv = lambda sa, iv, **kw: sa.crypt_salt + iv + b'\x00\x00\x00\x01' # noqa: E501
  448. CRYPT_ALGOS['AES-CTR'] = CryptAlgo('AES-CTR',
  449. cipher=algorithms.AES,
  450. mode=modes.CTR,
  451. iv_size=8,
  452. salt_size=4,
  453. format_mode_iv=_aes_ctr_format_mode_iv)
  454. _salt_format_mode_iv = lambda sa, iv, **kw: sa.crypt_salt + iv
  455. CRYPT_ALGOS['AES-GCM'] = CryptAlgo('AES-GCM',
  456. cipher=algorithms.AES,
  457. mode=modes.GCM,
  458. salt_size=4,
  459. iv_size=8,
  460. icv_size=16,
  461. format_mode_iv=_salt_format_mode_iv)
  462. if hasattr(modes, 'CCM'):
  463. CRYPT_ALGOS['AES-CCM'] = CryptAlgo('AES-CCM',
  464. cipher=algorithms.AES,
  465. mode=modes.CCM,
  466. iv_size=8,
  467. salt_size=3,
  468. icv_size=16,
  469. format_mode_iv=_salt_format_mode_iv)
  470. # XXX: Flagged as weak by 'cryptography'. Kept for backward compatibility
  471. CRYPT_ALGOS['Blowfish'] = CryptAlgo('Blowfish',
  472. cipher=algorithms.Blowfish,
  473. mode=modes.CBC)
  474. # XXX: RFC7321 states that DES *MUST NOT* be implemented.
  475. # XXX: Keep for backward compatibility?
  476. # Using a TripleDES cipher algorithm for DES is done by using the same 64
  477. # bits key 3 times (done by cryptography when given a 64 bits key)
  478. CRYPT_ALGOS['DES'] = CryptAlgo('DES',
  479. cipher=TripleDES, # Updated import path
  480. mode=modes.CBC,
  481. key_size=(8,))
  482. CRYPT_ALGOS['3DES'] = CryptAlgo('3DES',
  483. cipher=TripleDES, # Updated import path
  484. mode=modes.CBC)
  485. CRYPT_ALGOS['CAST'] = CryptAlgo('CAST',
  486. cipher=algorithms.CAST5,
  487. mode=modes.CBC)
  488. ###############################################################################
  489. if conf.crypto_valid:
  490. from cryptography.hazmat.primitives.hmac import HMAC
  491. from cryptography.hazmat.primitives.cmac import CMAC
  492. from cryptography.hazmat.primitives import hashes
  493. else:
  494. # no error if cryptography is not available but authentication won't be supported # noqa: E501
  495. HMAC = CMAC = hashes = None
  496.  
  497. ###############################################################################
  498.  
  499.  
  500. class IPSecIntegrityError(Exception):
  501. """
  502. Error risen when the integrity check fails.
  503. """
  504. pass
  505.  
  506.  
  507. class AuthAlgo(object):
  508. """
  509. IPsec integrity algorithm
  510. """
  511.  
  512. def __init__(self, name, mac, digestmod, icv_size, key_size=None):
  513. """
  514. :param name: the name of this integrity algorithm
  515. :param mac: a Message Authentication Code module
  516. :param digestmod: a Hash or Cipher module
  517. :param icv_size: the length of the integrity check value of this algo
  518. :param key_size: an integer or list/tuple of integers. If specified,
  519. force the secret keys length to one of the values.
  520. Defaults to the `key_size` of the cipher.
  521. """
  522. self.name = name
  523. self.mac = mac
  524. self.digestmod = digestmod
  525. self.icv_size = icv_size
  526. self.key_size = key_size
  527.  
  528. def check_key(self, key):
  529. """
  530. Check that the key length is valid.
  531.  
  532. :param key: a byte string
  533. """
  534. if self.key_size and len(key) not in self.key_size:
  535. raise TypeError('invalid key size %s, must be one of %s' %
  536. (len(key), self.key_size))
  537.  
  538. @crypto_validator
  539. def new_mac(self, key):
  540. """
  541. :param key: a byte string
  542. :returns: an initialized mac object for this algo
  543. """
  544. if self.mac is CMAC:
  545. return self.mac(self.digestmod(key), default_backend())
  546. else:
  547. return self.mac(key, self.digestmod(), default_backend())
  548.  
  549. def sign(self, pkt, key, esn_en=False, esn=0):
  550. """
  551. Sign an IPsec (ESP or AH) packet with this algo.
  552.  
  553. :param pkt: a packet that contains a valid encrypted ESP or AH layer
  554. :param key: the authentication key, a byte string
  555. :param esn_en: extended sequence number enable which allows to use
  556. 64-bit sequence number instead of 32-bit
  557. :param esn: extended sequence number (32 MSB)
  558.  
  559. :returns: the signed packet
  560. """
  561. if not self.mac:
  562. return pkt
  563.  
  564. mac = self.new_mac(key)
  565.  
  566. if pkt.haslayer(ESP):
  567. mac.update(raw(pkt[ESP]))
  568. pkt[ESP].data += mac.finalize()[:self.icv_size]
  569.  
  570. elif pkt.haslayer(AH):
  571. clone = zero_mutable_fields(pkt.copy(), sending=True)
  572. if esn_en:
  573. temp = raw(clone) + struct.pack('!L', esn)
  574. else:
  575. temp = raw(clone)
  576. mac.update(temp)
  577. pkt[AH].icv = mac.finalize()[:self.icv_size]
  578.  
  579. return pkt
  580.  
  581. def verify(self, pkt, key, esn_en=False, esn=0):
  582. """
  583. Check that the integrity check value (icv) of a packet is valid.
  584.  
  585. :param pkt: a packet that contains a valid encrypted ESP or AH layer
  586. :param key: the authentication key, a byte string
  587. :param esn_en: extended sequence number enable which allows to use
  588. 64-bit sequence number instead of 32-bit
  589. :param esn: extended sequence number (32 MSB)
  590.  
  591. :raise scapy.layers.ipsec.IPSecIntegrityError: if the integrity check
  592. fails
  593. """
  594. if not self.mac or self.icv_size == 0:
  595. return
  596.  
  597. mac = self.new_mac(key)
  598.  
  599. pkt_icv = 'not found'
  600.  
  601. if isinstance(pkt, ESP):
  602. pkt_icv = pkt.data[len(pkt.data) - self.icv_size:]
  603. clone = pkt.copy()
  604. clone.data = clone.data[:len(clone.data) - self.icv_size]
  605. temp = raw(clone)
  606.  
  607. elif pkt.haslayer(AH):
  608. if len(pkt[AH].icv) != self.icv_size:
  609. # Fill padding since we know the actual icv_size
  610. pkt[AH].padding = pkt[AH].icv[self.icv_size:]
  611. pkt[AH].icv = pkt[AH].icv[:self.icv_size]
  612. pkt_icv = pkt[AH].icv
  613. clone = zero_mutable_fields(pkt.copy(), sending=False)
  614. if esn_en:
  615. temp = raw(clone) + struct.pack('!L', esn)
  616. else:
  617. temp = raw(clone)
  618.  
  619. mac.update(temp)
  620. computed_icv = mac.finalize()[:self.icv_size]
  621.  
  622. # XXX: Cannot use mac.verify because the ICV can be truncated
  623. if pkt_icv != computed_icv:
  624. raise IPSecIntegrityError('pkt_icv=%r, computed_icv=%r' %
  625. (pkt_icv, computed_icv))
  626.  
  627. ###############################################################################
  628. # The names of the integrity algorithms are the same than in scapy.contrib.ikev2 # noqa: E501
  629. # see http://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml
  630.  
  631.  
  632. AUTH_ALGOS = {
  633. 'NULL': AuthAlgo('NULL', mac=None, digestmod=None, icv_size=0),
  634. }
  635.  
  636. if HMAC and hashes:
  637. # XXX: NIST has deprecated SHA1 but is required by RFC7321
  638. AUTH_ALGOS['HMAC-SHA1-96'] = AuthAlgo('HMAC-SHA1-96',
  639. mac=HMAC,
  640. digestmod=hashes.SHA1,
  641. icv_size=12)
  642. AUTH_ALGOS['SHA2-256-128'] = AuthAlgo('SHA2-256-128',
  643. mac=HMAC,
  644. digestmod=hashes.SHA256,
  645. icv_size=16)
  646. AUTH_ALGOS['SHA2-384-192'] = AuthAlgo('SHA2-384-192',
  647. mac=HMAC,
  648. digestmod=hashes.SHA384,
  649. icv_size=24)
  650. AUTH_ALGOS['SHA2-512-256'] = AuthAlgo('SHA2-512-256',
  651. mac=HMAC,
  652. digestmod=hashes.SHA512,
  653. icv_size=32)
  654. # XXX:Flagged as deprecated by 'cryptography'. Kept for backward compat
  655. AUTH_ALGOS['HMAC-MD5-96'] = AuthAlgo('HMAC-MD5-96',
  656. mac=HMAC,
  657. digestmod=hashes.MD5,
  658. icv_size=12)
  659. if CMAC and algorithms:
  660. AUTH_ALGOS['AES-CMAC-96'] = AuthAlgo('AES-CMAC-96',
  661. mac=CMAC,
  662. digestmod=algorithms.AES,
  663. icv_size=12,
  664. key_size=(16,))
  665.  
  666. ###############################################################################
  667.  
  668.  
  669. def split_for_transport(orig_pkt, transport_proto):
  670. """
  671. Split an IP(v6) packet in the correct location to insert an ESP or AH
  672. header.
  673.  
  674. :param orig_pkt: the packet to split. Must be an IP or IPv6 packet
  675. :param transport_proto: the IPsec protocol number that will be inserted
  676. at the split position.
  677. :returns: a tuple (header, nh, payload) where nh is the protocol number of
  678. payload.
  679. """
  680. # force resolution of default fields to avoid padding errors
  681. header = orig_pkt.__class__(raw(orig_pkt))
  682. next_hdr = header.payload
  683. nh = None
  684.  
  685. if header.version == 4:
  686. nh = header.proto
  687. header.proto = transport_proto
  688. header.remove_payload()
  689. del header.chksum
  690. del header.len
  691.  
  692. return header, nh, next_hdr
  693. else:
  694. found_rt_hdr = False
  695. prev = header
  696.  
  697. # Since the RFC 4302 is vague about where the ESP/AH headers should be
  698. # inserted in IPv6, I chose to follow the linux implementation.
  699. while isinstance(next_hdr, (IPv6ExtHdrHopByHop, IPv6ExtHdrRouting, IPv6ExtHdrDestOpt)): # noqa: E501
  700. if isinstance(next_hdr, IPv6ExtHdrHopByHop):
  701. pass
  702. if isinstance(next_hdr, IPv6ExtHdrRouting):
  703. found_rt_hdr = True
  704. elif isinstance(next_hdr, IPv6ExtHdrDestOpt) and found_rt_hdr:
  705. break
  706.  
  707. prev = next_hdr
  708. next_hdr = next_hdr.payload
  709.  
  710. nh = prev.nh
  711. prev.nh = transport_proto
  712. prev.remove_payload()
  713. del header.plen
  714.  
  715. return header, nh, next_hdr
  716.  
  717.  
  718. ###############################################################################
  719. # see RFC 4302 - Appendix A. Mutability of IP Options/Extension Headers
  720. IMMUTABLE_IPV4_OPTIONS = (
  721. 0, # End Of List
  722. 1, # No OPeration
  723. 2, # Security
  724. 5, # Extended Security
  725. 6, # Commercial Security
  726. 20, # Router Alert
  727. 21, # Sender Directed Multi-Destination Delivery
  728. )
  729.  
  730.  
  731. def zero_mutable_fields(pkt, sending=False):
  732. """
  733. When using AH, all "mutable" fields must be "zeroed" before calculating
  734. the ICV. See RFC 4302, Section 3.3.3.1. Handling Mutable Fields.
  735.  
  736. :param pkt: an IP(v6) packet containing an AH layer.
  737. NOTE: The packet will be modified
  738. :param sending: if true, ipv6 routing headers will not be reordered
  739. """
  740.  
  741. if pkt.haslayer(AH):
  742. pkt[AH].icv = b"\x00" * len(pkt[AH].icv)
  743. else:
  744. raise TypeError('no AH layer found')
  745.  
  746. if pkt.version == 4:
  747. # the tos field has been replaced by DSCP and ECN
  748. # Routers may rewrite the DS field as needed to provide a
  749. # desired local or end-to-end service
  750. pkt.tos = 0
  751. # an intermediate router might set the DF bit, even if the source
  752. # did not select it.
  753. pkt.flags = 0
  754. # changed en route as a normal course of processing by routers
  755. pkt.ttl = 0
  756. # will change if any of these other fields change
  757. pkt.chksum = 0
  758.  
  759. immutable_opts = []
  760. for opt in pkt.options:
  761. if opt.option in IMMUTABLE_IPV4_OPTIONS:
  762. immutable_opts.append(opt)
  763. else:
  764. immutable_opts.append(Raw(b"\x00" * len(opt)))
  765. pkt.options = immutable_opts
  766.  
  767. else:
  768. # holds DSCP and ECN
  769. pkt.tc = 0
  770. # The flow label described in AHv1 was mutable, and in RFC 2460 [DH98]
  771. # was potentially mutable. To retain compatibility with existing AH
  772. # implementations, the flow label is not included in the ICV in AHv2.
  773. pkt.fl = 0
  774. # same as ttl
  775. pkt.hlim = 0
  776.  
  777. next_hdr = pkt.payload
  778.  
  779. while isinstance(next_hdr, (IPv6ExtHdrHopByHop, IPv6ExtHdrRouting, IPv6ExtHdrDestOpt)): # noqa: E501
  780. if isinstance(next_hdr, (IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt)):
  781. for opt in next_hdr.options:
  782. if opt.otype & 0x20:
  783. # option data can change en-route and must be zeroed
  784. opt.optdata = b"\x00" * opt.optlen
  785. elif isinstance(next_hdr, IPv6ExtHdrRouting) and sending:
  786. # The sender must order the field so that it appears as it
  787. # will at the receiver, prior to performing the ICV computation. # noqa: E501
  788. next_hdr.segleft = 0
  789. if next_hdr.addresses:
  790. final = next_hdr.addresses.pop()
  791. next_hdr.addresses.insert(0, pkt.dst)
  792. pkt.dst = final
  793. else:
  794. break
  795.  
  796. next_hdr = next_hdr.payload
  797.  
  798. return pkt
  799.  
  800. ###############################################################################
  801.  
  802.  
  803. class SecurityAssociation(object):
  804. """
  805. This class is responsible of "encryption" and "decryption" of IPsec packets. # noqa: E501
  806. """
  807.  
  808. SUPPORTED_PROTOS = (IP, IPv6)
  809.  
  810. def __init__(self, proto, spi, seq_num=1, crypt_algo=None, crypt_key=None,
  811. auth_algo=None, auth_key=None, tunnel_header=None, nat_t_header=None, esn_en=False, esn=0): # noqa: E501
  812. """
  813. :param proto: the IPsec proto to use (ESP or AH)
  814. :param spi: the Security Parameters Index of this SA
  815. :param seq_num: the initial value for the sequence number on encrypted
  816. packets
  817. :param crypt_algo: the encryption algorithm name (only used with ESP)
  818. :param crypt_key: the encryption key (only used with ESP)
  819. :param auth_algo: the integrity algorithm name
  820. :param auth_key: the integrity key
  821. :param tunnel_header: an instance of a IP(v6) header that will be used
  822. to encapsulate the encrypted packets.
  823. :param nat_t_header: an instance of a UDP header that will be used
  824. for NAT-Traversal.
  825. :param esn_en: extended sequence number enable which allows to use
  826. 64-bit sequence number instead of 32-bit when using an
  827. AEAD algorithm
  828. :param esn: extended sequence number (32 MSB)
  829. """
  830.  
  831. if proto not in (ESP, AH, ESP.name, AH.name):
  832. raise ValueError("proto must be either ESP or AH")
  833. if isinstance(proto, six.string_types):
  834. self.proto = eval(proto)
  835. else:
  836. self.proto = proto
  837.  
  838. self.spi = spi
  839. self.seq_num = seq_num
  840. self.esn_en = esn_en
  841. # Get Extended Sequence (32 MSB)
  842. self.esn = esn
  843. if crypt_algo:
  844. if crypt_algo not in CRYPT_ALGOS:
  845. raise TypeError('unsupported encryption algo %r, try %r' %
  846. (crypt_algo, list(CRYPT_ALGOS)))
  847. self.crypt_algo = CRYPT_ALGOS[crypt_algo]
  848.  
  849. if crypt_key:
  850. salt_size = self.crypt_algo.salt_size
  851. self.crypt_key = crypt_key[:len(crypt_key) - salt_size]
  852. self.crypt_salt = crypt_key[len(crypt_key) - salt_size:]
  853. else:
  854. self.crypt_key = None
  855. self.crypt_salt = None
  856.  
  857. else:
  858. self.crypt_algo = CRYPT_ALGOS['NULL']
  859. self.crypt_key = None
  860. self.crypt_salt = None
  861.  
  862. if auth_algo:
  863. if auth_algo not in AUTH_ALGOS:
  864. raise TypeError('unsupported integrity algo %r, try %r' %
  865. (auth_algo, list(AUTH_ALGOS)))
  866. self.auth_algo = AUTH_ALGOS[auth_algo]
  867. self.auth_key = auth_key
  868. else:
  869. self.auth_algo = AUTH_ALGOS['NULL']
  870. self.auth_key = None
  871.  
  872. if tunnel_header and not isinstance(tunnel_header, (IP, IPv6)):
  873. raise TypeError('tunnel_header must be %s or %s' % (IP.name, IPv6.name)) # noqa: E501
  874. self.tunnel_header = tunnel_header
  875.  
  876. if nat_t_header:
  877. if proto is not ESP:
  878. raise TypeError('nat_t_header is only allowed with ESP')
  879. if not isinstance(nat_t_header, UDP):
  880. raise TypeError('nat_t_header must be %s' % UDP.name)
  881. self.nat_t_header = nat_t_header
  882.  
  883. def check_spi(self, pkt):
  884. if pkt.spi != self.spi:
  885. raise TypeError('packet spi=0x%x does not match the SA spi=0x%x' %
  886. (pkt.spi, self.spi))
  887.  
  888. def _encrypt_esp(self, pkt, seq_num=None, iv=None, esn_en=None, esn=None):
  889.  
  890. if iv is None:
  891. iv = self.crypt_algo.generate_iv()
  892. else:
  893. if len(iv) != self.crypt_algo.iv_size:
  894. raise TypeError('iv length must be %s' % self.crypt_algo.iv_size) # noqa: E501
  895.  
  896. esp = _ESPPlain(spi=self.spi, seq=seq_num or self.seq_num, iv=iv)
  897.  
  898. if self.tunnel_header:
  899. tunnel = self.tunnel_header.copy()
  900.  
  901. if tunnel.version == 4:
  902. del tunnel.proto
  903. del tunnel.len
  904. del tunnel.chksum
  905. else:
  906. del tunnel.nh
  907. del tunnel.plen
  908.  
  909. pkt = tunnel.__class__(raw(tunnel / pkt))
  910.  
  911. ip_header, nh, payload = split_for_transport(pkt, socket.IPPROTO_ESP)
  912. esp.data = payload
  913. esp.nh = nh
  914.  
  915. esp = self.crypt_algo.pad(esp)
  916. esp = self.crypt_algo.encrypt(self, esp, self.crypt_key,
  917. esn_en=esn_en or self.esn_en,
  918. esn=esn or self.esn)
  919.  
  920. self.auth_algo.sign(esp, self.auth_key)
  921.  
  922. if self.nat_t_header:
  923. nat_t_header = self.nat_t_header.copy()
  924. nat_t_header.chksum = 0
  925. del nat_t_header.len
  926. if ip_header.version == 4:
  927. del ip_header.proto
  928. else:
  929. del ip_header.nh
  930. ip_header /= nat_t_header
  931.  
  932. if ip_header.version == 4:
  933. ip_header.len = len(ip_header) + len(esp)
  934. del ip_header.chksum
  935. ip_header = ip_header.__class__(raw(ip_header))
  936. else:
  937. ip_header.plen = len(ip_header.payload) + len(esp)
  938.  
  939. # sequence number must always change, unless specified by the user
  940. if seq_num is None:
  941. self.seq_num += 1
  942.  
  943. return ip_header / esp
  944.  
  945. def _encrypt_ah(self, pkt, seq_num=None, esn_en=False, esn=0):
  946.  
  947. ah = AH(spi=self.spi, seq=seq_num or self.seq_num,
  948. icv=b"\x00" * self.auth_algo.icv_size)
  949.  
  950. if self.tunnel_header:
  951. tunnel = self.tunnel_header.copy()
  952.  
  953. if tunnel.version == 4:
  954. del tunnel.proto
  955. del tunnel.len
  956. del tunnel.chksum
  957. else:
  958. del tunnel.nh
  959. del tunnel.plen
  960.  
  961. pkt = tunnel.__class__(raw(tunnel / pkt))
  962.  
  963. ip_header, nh, payload = split_for_transport(pkt, socket.IPPROTO_AH)
  964. ah.nh = nh
  965.  
  966. if ip_header.version == 6 and len(ah) % 8 != 0:
  967. # For IPv6, the total length of the header must be a multiple of
  968. # 8-octet units.
  969. ah.padding = b"\x00" * (-len(ah) % 8)
  970. elif len(ah) % 4 != 0:
  971. # For IPv4, the total length of the header must be a multiple of
  972. # 4-octet units.
  973. ah.padding = b"\x00" * (-len(ah) % 4)
  974.  
  975. # RFC 4302 - Section 2.2. Payload Length
  976. # This 8-bit field specifies the length of AH in 32-bit words (4-byte
  977. # units), minus "2".
  978. ah.payloadlen = len(ah) // 4 - 2
  979.  
  980. if ip_header.version == 4:
  981. ip_header.len = len(ip_header) + len(ah) + len(payload)
  982. del ip_header.chksum
  983. ip_header = ip_header.__class__(raw(ip_header))
  984. else:
  985. ip_header.plen = len(ip_header.payload) + len(ah) + len(payload)
  986.  
  987. signed_pkt = self.auth_algo.sign(ip_header / ah / payload,
  988. self.auth_key,
  989. esn_en=esn_en or self.esn_en,
  990. esn=esn or self.esn)
  991.  
  992. # sequence number must always change, unless specified by the user
  993. if seq_num is None:
  994. self.seq_num += 1
  995.  
  996. return signed_pkt
  997.  
  998. def encrypt(self, pkt, seq_num=None, iv=None, esn_en=None, esn=None):
  999. """
  1000. Encrypt (and encapsulate) an IP(v6) packet with ESP or AH according
  1001. to this SecurityAssociation.
  1002.  
  1003. :param pkt: the packet to encrypt
  1004. :param seq_num: if specified, use this sequence number instead of the
  1005. generated one
  1006. :param esn_en: extended sequence number enable which allows to
  1007. use 64-bit sequence number instead of 32-bit when
  1008. using an AEAD algorithm
  1009. :param esn: extended sequence number (32 MSB)
  1010. :param iv: if specified, use this initialization vector for
  1011. encryption instead of a random one.
  1012.  
  1013. :returns: the encrypted/encapsulated packet
  1014. """
  1015. if not isinstance(pkt, self.SUPPORTED_PROTOS):
  1016. raise TypeError('cannot encrypt %s, supported protos are %s'
  1017. % (pkt.__class__, self.SUPPORTED_PROTOS))
  1018. if self.proto is ESP:
  1019. return self._encrypt_esp(pkt, seq_num=seq_num,
  1020. iv=iv, esn_en=esn_en,
  1021. esn=esn)
  1022. else:
  1023. return self._encrypt_ah(pkt, seq_num=seq_num,
  1024. esn_en=esn_en, esn=esn)
  1025.  
  1026. def _decrypt_esp(self, pkt, verify=True, esn_en=None, esn=None):
  1027.  
  1028. encrypted = pkt[ESP]
  1029.  
  1030. if verify:
  1031. self.check_spi(pkt)
  1032. self.auth_algo.verify(encrypted, self.auth_key)
  1033.  
  1034. esp = self.crypt_algo.decrypt(self, encrypted, self.crypt_key,
  1035. self.crypt_algo.icv_size or
  1036. self.auth_algo.icv_size,
  1037. esn_en=esn_en or self.esn_en,
  1038. esn=esn or self.esn)
  1039.  
  1040. if self.tunnel_header:
  1041. # drop the tunnel header and return the payload untouched
  1042.  
  1043. pkt.remove_payload()
  1044. if pkt.version == 4:
  1045. pkt.proto = esp.nh
  1046. else:
  1047. pkt.nh = esp.nh
  1048. cls = pkt.guess_payload_class(esp.data)
  1049.  
  1050. return cls(esp.data)
  1051. else:
  1052. ip_header = pkt
  1053.  
  1054. if ip_header.version == 4:
  1055. ip_header.proto = esp.nh
  1056. del ip_header.chksum
  1057. ip_header.remove_payload()
  1058. ip_header.len = len(ip_header) + len(esp.data)
  1059. # recompute checksum
  1060. ip_header = ip_header.__class__(raw(ip_header))
  1061. else:
  1062. encrypted.underlayer.nh = esp.nh
  1063. encrypted.underlayer.remove_payload()
  1064. ip_header.plen = len(ip_header.payload) + len(esp.data)
  1065.  
  1066. cls = ip_header.guess_payload_class(esp.data)
  1067.  
  1068. # reassemble the ip_header with the ESP payload
  1069. return ip_header / cls(esp.data)
  1070.  
  1071. def _decrypt_ah(self, pkt, verify=True, esn_en=None, esn=None):
  1072.  
  1073. if verify:
  1074. self.check_spi(pkt)
  1075. self.auth_algo.verify(pkt, self.auth_key,
  1076. esn_en=esn_en or self.esn_en,
  1077. esn=esn or self.esn)
  1078.  
  1079. ah = pkt[AH]
  1080. payload = ah.payload
  1081. payload.remove_underlayer(None) # useless argument...
  1082.  
  1083. if self.tunnel_header:
  1084. return payload
  1085. else:
  1086. ip_header = pkt
  1087.  
  1088. if ip_header.version == 4:
  1089. ip_header.proto = ah.nh
  1090. del ip_header.chksum
  1091. ip_header.remove_payload()
  1092. ip_header.len = len(ip_header) + len(payload)
  1093. # recompute checksum
  1094. ip_header = ip_header.__class__(raw(ip_header))
  1095. else:
  1096. ah.underlayer.nh = ah.nh
  1097. ah.underlayer.remove_payload()
  1098. ip_header.plen = len(ip_header.payload) + len(payload)
  1099.  
  1100. # reassemble the ip_header with the AH payload
  1101. return ip_header / payload
  1102.  
  1103. def decrypt(self, pkt, verify=True, esn_en=None, esn=None):
  1104. """
  1105. Decrypt (and decapsulate) an IP(v6) packet containing ESP or AH.
  1106.  
  1107. :param pkt: the packet to decrypt
  1108. :param verify: if False, do not perform the integrity check
  1109. :param esn_en: extended sequence number enable which allows to use
  1110. 64-bit sequence number instead of 32-bit when using an
  1111. AEAD algorithm
  1112. :param esn: extended sequence number (32 MSB)
  1113. :returns: the decrypted/decapsulated packet
  1114. :raise scapy.layers.ipsec.IPSecIntegrityError: if the integrity check
  1115. fails
  1116. """
  1117. if not isinstance(pkt, self.SUPPORTED_PROTOS):
  1118. raise TypeError('cannot decrypt %s, supported protos are %s'
  1119. % (pkt.__class__, self.SUPPORTED_PROTOS))
  1120.  
  1121. if self.proto is ESP and pkt.haslayer(ESP):
  1122. return self._decrypt_esp(pkt, verify=verify,
  1123. esn_en=esn_en, esn=esn)
  1124. elif self.proto is AH and pkt.haslayer(AH):
  1125. return self._decrypt_ah(pkt, verify=verify, esn_en=esn_en, esn=esn)
  1126. else:
  1127. raise TypeError('%s has no %s layer' % (pkt, self.proto.name))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement