protean

package module
v0.0.0-...-39f08af Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 4, 2020 License: MIT Imports: 10 Imported by: 0

README

The Operator Foundation

Operator makes useable tools to help people around the world with censorship, security, and privacy.

Shapeshifter

The Shapeshifter project provides network protocol shapeshifting technology (also sometimes referred to as obfuscation). The purpose of this technology is to change the characteristics of network traffic so that it is not identified and subsequently blocked by network filtering devices.

There are two primary components to Shapeshifter: transports and the dispatcher. Each transport provide different approach to shapeshifting. These transports are provided as a Go library which can be integrated directly into applications. The dispatcher is a command line tool which provides a proxy that wraps the transport library. It has several different proxy modes and can proxy both TCP and UDP traffic.

If you are a tool developer working in the Go programming language, then you probably want to use the transports library directly in your application. https://github.com/OperatorFoundation/shapeshifter-transports

If you want a end user that is trying to circumvent filtering on your network or you are a developer that wants to add pluggable transports to an existing tool that is not written in the Go programming language, then you probably want the dispatcher. Please note that familiarity with executing programs on the command line is necessary to use this tool. https://github.com/OperatorFoundation/shapeshifter-dispatcher

If you are looking for a complete, easy-to-use VPN that incorporates shapeshifting technology and has a graphical user interface, consider Moonbounce, an application for macOS which incorporates shapeshifting without the need to write code or use the command line.

Protean

Protean is a collection of transformers designed for the purpose of obfuscating UDP network traffic.

This is a port of the Typescript implementation originally developed as a part of uProxy.

The overall goal of Protean is to provide transformations from UDP traffic into other UDP traffic, where the target UDP traffic has properties that resist network filtering. This is in contract to tools such as Shapeshifter Dispatcher, which provide resistance to network filtering by tunneling UDP traffic over TCP protocols.

Currently, Protean is provided as a library of open source transformation functions. A possible future goal is to integrate these transformations into transports for the Shapeshifter Transports library, with integration into Shapeshifter Dispatcher. Before this can happen, the Pluggable Transports specification needs to be updated to allow for UDP-to-UDP transports. Currently in the PT 2.0 specification, UDP is supported, but only in the case of UDP-over-TCP.

Documentation

Index

Constants

View Source
const BOTTOM_VALUE uint32 = TOP_VALUE >> 8

The lowest possible value. Anything lower than this will be shifted up during renormalization.

View Source
const CACHE_EXPIRATION_TIME time.Duration = time.Duration(60 * 1000)

Cache expiration is set to 60 seconds.

View Source
const CHUNK_SIZE = 16
View Source
const CODE_BITS uint32 = 32

The precision of the arithmetic coder

View Source
const EXTRA_BITS uint32 = (CODE_BITS-2)%8 + 1

Tne number of bits left over during renormalization.

View Source
const HEADER_SIZE int = 2 + 32 + 1 + 1

Header size: length + id + fragment number + total number

View Source
const IV_SIZE = 16
View Source
const MAX_INT uint32 = 4294967295

The maximum possible unsigned value given the precision of the coder. (2^32)-1

View Source
const SHIFT_BITS uint32 = CODE_BITS - 9

The number of bits to shift over during renormalization.

View Source
const TOP_VALUE uint32 = 2147483648

The maximum possible signed value given the precision of the coder. 2^(32-1)

Variables

This section is empty.

Functions

func SaveProbs

func SaveProbs(items []uint32) ([]byte, error)

Takes a list of numbers where the inputs should all be integers from 0 to 255 and converts them to bytes in an []byte.

Types

type ByteSequenceShaper

type ByteSequenceShaper struct {
	// Sequences that should be added to the outgoing packet stream.
	AddSequences []*SequenceModel

	// Sequences that should be removed from the incoming packet stream.
	RemoveSequences []*SequenceModel

	// Index of the first packet to be injected into the stream.
	FirstIndex int8

	// Index of the last packet to be injected into the stream.
	LastIndex int8

	// Current Index into the output stream.
	// This starts at zero and is incremented every time a packet is output.
	// The OutputIndex is compared to the SequenceModel Index. When they are
	// equal, a byte Sequence packet is injected into the output.
	OutputIndex int8
}

An obfuscator that injects byte sequences.

func NewByteSequenceShaper

func NewByteSequenceShaper() *ByteSequenceShaper

func (*ByteSequenceShaper) Configure

func (shaper *ByteSequenceShaper) Configure(jsonConfig string)

Configure the Transformer with the headers to inject and the headers to remove.

func (*ByteSequenceShaper) ConfigureStruct

func (shaper *ByteSequenceShaper) ConfigureStruct(config SequenceConfig)

func (*ByteSequenceShaper) Dispose

func (shaper *ByteSequenceShaper) Dispose()

No-op (we have no state or any resources to Dispose).

func (*ByteSequenceShaper) Inject

func (shaper *ByteSequenceShaper) Inject(results [][]byte) [][]byte

Inject packets

func (*ByteSequenceShaper) OutputAndIncrement

func (shaper *ByteSequenceShaper) OutputAndIncrement(results [][]byte, result []byte) [][]byte

func (*ByteSequenceShaper) Restore

func (shaper *ByteSequenceShaper) Restore(buffer []byte) [][]byte

Remove injected packets.

func (*ByteSequenceShaper) SetKey

func (shaper *ByteSequenceShaper) SetKey(key []byte)

This method is required to implement the Transformer API. @param {[]byte} key Key to set, not used by this class.

func (*ByteSequenceShaper) Transform

func (shaper *ByteSequenceShaper) Transform(buffer []byte) [][]byte

Inject header.

type Coder

type Coder struct {
	// contains filtered or unexported fields
}

The state and initialiation code for arithmetic coding. This class is never instantiated directly. The subclasses Encoder and Decoder are used instead.

func NewCoder

func NewCoder(probs []uint32) Coder

The Coder constructor normalizes the symbol probabilities and build the coding table.

type Decoder

type Decoder struct {
	//extends Coder
	Coder
}

Decodes a sequence of bytes using a probability distribution with the goal of yielding a lower entropy sequence of bytes.

func NewDecoder

func NewDecoder(probs []uint32) Decoder

func (*Decoder) Decode

func (this *Decoder) Decode(input []byte) []byte

Decode a sequence of bytes

type DecompressionConfig

type DecompressionConfig struct {
	Frequencies []uint32
}

type DecompressionShaper

type DecompressionShaper struct {
	Frequencies []uint32
	// contains filtered or unexported fields
}

A Transformer that uses an arithmetic coder to change the entropy. This Transformer uses a somewhat unusual technique of reverse compression. The only instance I know of this being done previously is in Dust: http://github.com/blanu/Dust

Dust uses the reverse Huffman encoding describe in the book "Disappearing Cryptography" by Peter Wayner. Chapter 6.2 (p. 88) describes the technique as follows: "This chapter is about creating an automatic way of taking small, innocuous bits of data and embellishing them with deep, embroidered details until the result mimics something completely different. The data is hidden as it assumes this costume. The effect is accomplished here by running the Huffman compression algorithm described in Chapter 5 in reverse. Ordinarily, the Huffman algorithm would aprrxoimate the statistical distribution of the text and then convert it into a digital shorthand. Running this in reverse can take normal data and form it into elaborate patterns."

Dust uses a Huffman encoder, and statistical tests run on the results have shown that Huffman encoding has a limitation when used in this way. The probabilities of bytes can only be based on powers of two (1/2, 1/4, etc.). This limits its facility at mimicry if the mimicked distribution differs greatly from an approximation which is quantized into powers of two. Therefore, an arithmetic encoder is used here instead of a Huffman encoder. As far as I know, this is the first time this has been done, so the results compared to Huffman encoding are unknown.

The important thing to realize is that the compression algorithm is being run in reverse, contrary to normal expectations.

func NewDecompressionShaper

func NewDecompressionShaper() *DecompressionShaper

func (*DecompressionShaper) Configure

func (this *DecompressionShaper) Configure(jsonConfig string)

Configure the Transformer with the headers to inject and the headers to remove.

func (*DecompressionShaper) ConfigureStruct

func (this *DecompressionShaper) ConfigureStruct(config DecompressionConfig)

func (*DecompressionShaper) Dispose

func (shaper *DecompressionShaper) Dispose()

No-op (we have no state or any resources to Dispose).

func (*DecompressionShaper) Restore

func (shaper *DecompressionShaper) Restore(buffer []byte) [][]byte

func (*DecompressionShaper) SetKey

func (shaper *DecompressionShaper) SetKey(key []byte)

This method is required to implement the Transformer API. @param {[]byte} key Key to set, not used by this class.

func (*DecompressionShaper) Transform

func (shaper *DecompressionShaper) Transform(buffer []byte) [][]byte

Decompress the bytestream. The purpose of this Transform is to take a high entropy bytestream and produce a lower entropy one.

type Defragmenter

type Defragmenter struct {
	// contains filtered or unexported fields
}

The Defragmenter gathers fragmented packets in a buffer and defragments them. The cache expiration strategy is taken from RFC 815: IP Datagram Reassembly Algorithms.

func (*Defragmenter) AddFragment

func (this *Defragmenter) AddFragment(fragment *Fragment)

Add a fragment that has been received from the network. Fragments are processed according to the following logic:

If the packet identifier is recognized:
  If we have a fragment for this index:
    This fragment is a duplicate, drop it.
  Else:
   This fragment a new fragment for an existing packet
Else:
  This fragment a new fragment for a new packet.

func (*Defragmenter) CompleteCount

func (this *Defragmenter) CompleteCount() int

Returns the number of packets for which all fragments have arrived.

func (*Defragmenter) GetComplete

func (this *Defragmenter) GetComplete() [][]byte

Return an []byte for each packet where all fragments are available. Calling this clears the set of stored completed fragments.

type Encoder

type Encoder struct {
	// extends Coder
	Coder
}

Encodes a sequence of bytes using a probability distribution with the goal of yielding a higher entropy sequence of bytes.

func NewEncoder

func NewEncoder(probs []uint32) Encoder

func (*Encoder) Encode

func (this *Encoder) Encode(input []byte) []byte

Encode a sequence of bytes.

type EncryptionConfig

type EncryptionConfig struct {
	Key string
}

Accepted in serialised form by Configure().

type EncryptionShaper

type EncryptionShaper struct {
	// contains filtered or unexported fields
}

A packet shaper that encrypts the packets with AES CBC.

func NewEncryptionShaper

func NewEncryptionShaper() *EncryptionShaper

func (*EncryptionShaper) Configure

func (shaper *EncryptionShaper) Configure(jsonConfig string)

Configure the Transformer with the headers to inject and the headers to remove.

func (*EncryptionShaper) ConfigureStruct

func (shaper *EncryptionShaper) ConfigureStruct(config EncryptionConfig)

func (*EncryptionShaper) Dispose

func (shaper *EncryptionShaper) Dispose()

No-op (we have no state or any resources to Dispose).

func (*EncryptionShaper) Restore

func (shaper *EncryptionShaper) Restore(buffer []byte) [][]byte

func (*EncryptionShaper) SetKey

func (shaper *EncryptionShaper) SetKey(key []byte)

This method is required to implement the Transformer API. @param {[]byte} key Key to set, not used by this class.

func (*EncryptionShaper) Transform

func (shaper *EncryptionShaper) Transform(buffer []byte) [][]byte

Inject header.

type Fragment

type Fragment struct {
	Length  uint16
	Id      []byte
	Index   uint8
	Count   uint8
	Payload []byte
	Padding []byte
}

A Fragment represents a piece of a packet when fragmentation has occurred.

type FragmentationConfig

type FragmentationConfig struct {
	MaxLength uint16
}

Accepted in serialised form by Configure().

type FragmentationShaper

type FragmentationShaper struct {
	// contains filtered or unexported fields
}

A Transformer that enforces a maximum packet length.

func NewFragmentationShaper

func NewFragmentationShaper() *FragmentationShaper

func (*FragmentationShaper) Configure

func (shaper *FragmentationShaper) Configure(jsonConfig string)

Configure the Transformer with the headers to inject and the headers to remove.

func (*FragmentationShaper) ConfigureStruct

func (shaper *FragmentationShaper) ConfigureStruct(config FragmentationConfig)

func (*FragmentationShaper) Dispose

func (shaper *FragmentationShaper) Dispose()

No-op (we have no state or any resources to Dispose).

func (*FragmentationShaper) Restore

func (this *FragmentationShaper) Restore(buffer []byte) [][]byte

Perform the following steps: - Decode buffer into a fragment - Remove fill - Remove fragment headers - Attempt to defragment, yielding zero or more new buffers

func (*FragmentationShaper) SetKey

func (shaper *FragmentationShaper) SetKey(key []byte)

This method is required to implement the Transformer API. @param {[]byte} key Key to set, not used by this class.

func (*FragmentationShaper) Transform

func (this *FragmentationShaper) Transform(buffer []byte) [][]byte

Perform the following steps: - Break buffer into one or more fragments - Add fragment headers to each fragment - Add fill if necessary to pad each fragment to a multiple of CHUNK_SIZE - Encode fragments into new buffers

type HeaderConfig

type HeaderConfig struct {
	// Header that should be added to the beginning of each outgoing packet.
	AddHeader SerializedHeaderModel

	// Header that should be removed from each incoming packet.
	RemoveHeader SerializedHeaderModel
}

Accepted in serialised form by Configure().

type HeaderModel

type HeaderModel struct {
	// Header.
	Header []byte
}

Header models where the headers have been decoded as []bytes. This is used internally by the HeaderShaper.

type HeaderShaper

type HeaderShaper struct {
	// Headers that should be added to the outgoing packet stream.
	AddHeader HeaderModel

	// Headers that should be removed from the incoming packet stream.
	RemoveHeader HeaderModel
}

An obfuscator that injects headers.

func NewHeaderShaper

func NewHeaderShaper() *HeaderShaper

func (*HeaderShaper) Configure

func (headerShaper *HeaderShaper) Configure(jsonConfig string)

Configure the Transformer with the headers to inject and the headers to remove.

func (*HeaderShaper) ConfigureStruct

func (headerShaper *HeaderShaper) ConfigureStruct(config HeaderConfig)

func (*HeaderShaper) Dispose

func (headerShaper *HeaderShaper) Dispose()

No-op (we have no state or any resources to Dispose).

func (*HeaderShaper) Restore

func (headerShaper *HeaderShaper) Restore(buffer []byte) [][]byte

Remove injected header.

func (*HeaderShaper) SetKey

func (headerShaper *HeaderShaper) SetKey(key []byte)

This method is required to implement the Transformer API. @param {[]byte} key Key to set, not used by this class.

func (*HeaderShaper) Transform

func (headerShaper *HeaderShaper) Transform(buffer []byte) [][]byte

Inject header.

type Interval

type Interval struct {
	// contains filtered or unexported fields
}

Models a symbol as an interval in the arithmetic coding space

type PacketTracker

type PacketTracker struct {
	// Indexed lists of fragments for this packet
	Pieces [][]byte

	// Counts of the number remaining
	// This is an optimization to avoid scanning Pieces repeatedly for counts.
	Counter uint8

	// Stores the Timer objects for expiring each identifier
	// See RFC 815, section 7, paragraph 2 (p. 8)
	Timer *time.Timer
}

Tracks the fragments for a single packet identifier

type ProteanConfig

type ProteanConfig struct {
	// contains filtered or unexported fields
}

Accepted in serialised form by Configure().

type ProteanShaper

type ProteanShaper struct {
	// contains filtered or unexported fields
}

A packet shaper that composes multiple Transformers. The following Transformers are composed: - Fragmentation based on MTU and chunk size - AES encryption - decompression using arithmetic coding - byte sequence injection

func NewProteanShaper

func NewProteanShaper() *ProteanShaper

func (*ProteanShaper) Configure

func (this *ProteanShaper) Configure(jsonConfig string)

Configure the Transformer with the headers to inject and the headers to remove.

func (*ProteanShaper) Dispose

func (shaper *ProteanShaper) Dispose()

No-op (we have no state or any resources to Dispose).

func (*ProteanShaper) Restore

func (this *ProteanShaper) Restore(buffer []byte) [][]byte

Apply the following Transformations: - Discard injected packets - Discard injected headers - Decrypt with AES - Compress with arithmetic coding - Attempt defragmentation

func (*ProteanShaper) SetKey

func (shaper *ProteanShaper) SetKey(key []byte)

This method is required to implement the Transformer API. @param {[]byte} key Key to set, not used by this class.

func (*ProteanShaper) Transform

func (this *ProteanShaper) Transform(buffer []byte) [][]byte

Apply the following Transformations: - Fragment based on MTU and chunk size - Encrypt using AES - Decompress using arithmetic coding - Inject headers into packets - Inject packets with byte sequences

type SequenceConfig

type SequenceConfig struct {
	// Sequences that should be added to the outgoing packet stream.
	AddSequences []SerializedSequenceModel

	// Sequences that should be removed from the incoming packet stream.
	RemoveSequences []SerializedSequenceModel
}

Accepted in serialised form by Configure().

type SequenceModel

type SequenceModel struct {
	// Index of the packet into the stream.
	Index int8

	// Offset of the Sequence in the packet.
	Offset int16

	// Byte Sequence.
	Sequence []byte

	// Target packet Length.
	Length int16
}

Sequence models where the Sequences have been decoded as []bytes. This is used internally by the ByteSequenceShaper.

type SerializedHeaderModel

type SerializedHeaderModel struct {
	// Header encoded as a string.
	Header string
}

Header models where the headers have been encoded as strings. This is used by the HeaderConfig argument passed to Configure().

type SerializedSequenceModel

type SerializedSequenceModel struct {
	// Index of the packet into the Sequence.
	Index int8

	// Offset of the Sequence in the packet.
	Offset int16

	// Byte Sequence encoded as a string.
	Sequence string

	// Target packet Length.
	Length int16
}

Sequence models where the Sequences have been encoded as strings. This is used by the SequenceConfig argument passed to Configure().

type Transformer

type Transformer interface {
	/**
	 * Sets the key for this Transformer session.
	 *
	 * @param {[]byte} key session key.
	 * @return {boolean} true if successful.
	 */
	SetKey(key []byte)

	/**
	 * Configures this Transformer.
	 *
	 * @param {String} serialized Json string.
	 */
	Configure(json string)

	/**
	 * Transforms a piece of data to obfuscated form.
	 *
	 * @param {[]byte} plaintext data that needs to be obfuscated.
	 * @return {[]byte[]} list of []bytes of obfuscated data.
	 * The list can contain zero, one, or more than one items.
	 * In the case of fragmentation:
	 *   When fragmention occurs, the list will have more than one item.
	 *   When there is no fragmentation, the list will have one item.
	 */
	Transform(buffer []byte) [][]byte

	/**
	 * Restores data from obfuscated form to original form.
	 *
	 * @param {[]byte} ciphertext obfuscated data.
	 * @return {[]byte} list of []bytes of original data.
	 * The list can contain zero, one, or more than one items.
	 * In the case of fragmentation:
	 *   When receiving a fragment, the list will have zero items,
	 *   unless it was the last fragment, then the list will have one item.
	 */
	Restore(buffer []byte) [][]byte

	/**
	 * Dispose the Transformer.
	 *
	 * This should be the last method called on a Transformer instance.
	 */
	Dispose()
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL