Skip to content

Instantly share code, notes, and snippets.

@nuvious
Created June 25, 2024 18:18
Show Gist options
  • Save nuvious/b216145bcbba0f4199c14d66ba6a66e8 to your computer and use it in GitHub Desktop.
Save nuvious/b216145bcbba0f4199c14d66ba6a66e8 to your computer and use it in GitHub Desktop.
Cloak Covert Channel TCP Flow Sequence Encoder/Decoder
"""
An implementation of the encoding used by Clock [1], a timing based covert
channel which converts a binary string into a sequence of N packets to be sent
over X flows. It is assumed that the values N, X, and the number of bits per
message are agreed upon ahead of time. The bit string is converted to an
unsigned integer value, which is used as the rank [2] for the reverse-sorted
distribution. The distribution is then computed from this rank and each of X
tcp flows has N packets sent with each flow waiting for N acknowledgements
before attempting to receive the next message. On the receiving end, the number
of TCP handshakes is counted and the number of packets sent are also counted to
reproduce the distribution. The rank is then computed and converted back to
binary.
The below implements the encoding and decoding logic to the best of my
understanding from the paper.
Expected Output:
(base) nuvious@rpiterm:~/JHU/EN.695.722.81.SU24-CoverChannels$ python3 rank.py
(3, 4, 2, 5, 1) Rank: 55
55 Distribution: (3, 4, 2, 5, 1)
Lbits: 010100100110011100
84380
(16, 15, 14, 13, 12, 11, 10, 7, 9, 2, 6, 8, 1, 4, 3, 5)
Encoded TCP Info (tcp_flow_index, num_packets):
((0, 16), (1, 15), (2, 14), (3, 13), (4, 12), (5, 11), (6, 10), (7, 7),
(8, 9), (9, 2), (10, 6), (11, 8), (12, 1), (13, 4), (14, 3), (15, 5))
Decoded Lbits: 010100100110011100
(base) nuvious@rpiterm:~/JHU/EN.695.722.81.SU24-CoverChannels$
[1] X. Luo, E. Chan, and R. Chang, Cloak: A TenFold Way for Reliable Covert
Communications, vol. 4734. 2007, pp. 283–298.
doi: https://doi.org/10.1007/9783540748359_19
[2] Wikipedia Contributors, “Ranking (statistics),” Wikipedia, Dec. 05, 2023.
Available: https://en.wikipedia.org/wiki/Ranking_(statistics).
[Accessed: Jun. 25, 2024]
"""
import itertools
def rank(values: tuple):
"""Returns the reverse-orderd statistical rank of an ordered set of values
Parameters
----------
values : tuple
An ordered set of values which are in the range of [1..N]
Returns
-------
int
The reverse-order statistical rank
"""
sorted_values = sorted(list(values), reverse=True)
for i, permutation in enumerate(itertools.permutations(sorted_values)):
if permutation == values:
return i - 1
def unrank(rank: int, value_count: int):
"""Returns the sequence of values given a reverse-ordered rank
Parameters
----------
rank : int
The rank of the set
value_count : int
The number of values expected in the set
Returns
-------
tuple
The ordered values of the set
"""
sorted_values = list(range(value_count, 0, -1))
for i, permutation in enumerate(itertools.permutations(sorted_values)):
if i == rank + 1:
return permutation
def cloak_encode(N: int, X: int, lbits: str):
"""Encodes an l-bit string into a distribution of TCP flows and packet
counts.
Parameters
----------
N : int
Maximum number of packets per flow.
X : int
Number of flows
lbits : str
A binary string of 1's and 0's
Returns
-------
tuple
Tuple of (tcp_flow_index, num_packets)
"""
# Convert to unsigned int
lbits_rank = int(lbits, 2)
print(lbits_rank)
distribution = unrank(rank=lbits_rank, value_count=X)
print(distribution)
return tuple((i, distribution[i]) for i in range(X))
def cloak_decode(N: int, X: int, tcp_flow_data: tuple, lbit_len: int):
"""Decodes a tuple of (tcp_flow_index, num_packets) into an lbit string
Parameters
----------
N : int
Maximum number of packets per flow.
X : int
Number of flows
tcp_flow_data : tuple
Tuple of (tcp_flow_index, num_packets)
lbit_len : int
Length of bitstring expected
Returns
-------
str
The decoded bitstring
"""
distribution = tuple(
num_packets for tcp_packet_index, num_packets in tcp_flow_data
)
lbits_rank = rank(distribution)
return bin(lbits_rank)[2:].zfill(lbit_len)
if __name__ == "__main__":
N = 16
X = 16
values = (3, 4, 2, 5, 1)
lbits = '010100100110011100'
lbit_len = len(lbits)
values_rank = rank(values)
print(f"{values} Rank:", values_rank)
unranked_distribution = unrank(values_rank, len(values))
print(f"{values_rank} Distribution:", unranked_distribution)
print("Lbits:", lbits)
encoded = cloak_encode(N, X, lbits)
print("Encoded TCP Info (tcp_flow_index, num_packets):\n", encoded)
decoded = cloak_decode(N, X, encoded, lbit_len)
print("Decoded Lbits:", decoded)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment