code: def decrypt(self, esp, key, icv_size=None):
          
          if icv_size is None:
              icv_size = self.icv_size if self.is_aead else 0
  
          iv = esp.data[:self.iv_size]
          data = esp.data[self.iv_size:len(esp.data) - icv_size]
          icv = esp.data[len(esp.data) - icv_size:]
  
          if self.cipher:
              cipher = self.new_cipher(key, iv, icv)
              decryptor = cipher.decryptor()
  
              if self.is_aead:
                  # Tag value check is done during the finalize method
                  decryptor.authenticate_additional_data(
                      struct.pack('!LL', esp.spi, esp.seq)
                  )
  
              try:
                  data = decryptor.update(data) + decryptor.finalize()
              except InvalidTag as err:
                  raise IPSecIntegrityError(err)
  
          # extract padlen and nh
          padlen = (data[-2])
          nh = data[-1]
  
          # then use padlen to determine data and padding
          data = data[:len(data) - padlen - 2]
          padding = data[len(data) - padlen - 2: len(data) - 2]
  
          return _ESPPlain(spi=esp.spi,
                          seq=esp.seq,
                          iv=iv,
                          data=data,
                          padding=padding,
                          padlen=padlen,
                          nh=nh,
                          icv=icv)
docs: Decrypt an ESP packet
  
          @param esp:        an encrypted ESP packet
          @param key:        the secret key used for encryption
          @param icv_size:   the length of the icv used for integrity check
  
          @return:    a valid ESP packet encrypted with this algorithm
          @raise IPSecIntegrityError: if the integrity check fails with an AEAD
                                      algorithm