-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathprotean.go
148 lines (128 loc) · 4.65 KB
/
protean.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package protean
import (
"encoding/json"
"fmt"
)
// Accepted in serialised form by Configure().
type ProteanConfig struct {
decompression DecompressionConfig
encryption EncryptionConfig
fragmentation FragmentationConfig
injection SequenceConfig
headerInjection HeaderConfig
}
// Creates a sample (non-random) config, suitable for testing.
func sampleProteanConfig() ProteanConfig {
return ProteanConfig{decompression: sampleDecompressionConfig(), encryption: sampleEncryptionConfig(), fragmentation: sampleFragmentationConfig(), injection: sampleSequenceConfig(), headerInjection: sampleHeaderConfig()}
}
func flatMap(input [][]byte, mappedFunction func([]byte) [][]byte) [][]byte {
var accum [][]byte
for _, item := range input {
mapped := mappedFunction(item)
if accum == nil {
accum = mapped
} else {
accum = append(accum, mapped...)
}
}
return accum
}
// 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
type ProteanShaper struct {
// Fragmentation Transformer
fragmenter *FragmentationShaper
// Encryption Transformer
encrypter *EncryptionShaper
// Decompression Transformer
decompressor *DecompressionShaper
// Byte sequence injecter Transformer
injecter *ByteSequenceShaper
// Byte sequence injecter Transformer
headerinjecter *HeaderShaper
}
func NewProteanShaper() *ProteanShaper {
shaper := &ProteanShaper{}
config := sampleProteanConfig()
jsonConfig, err := json.Marshal(config)
if err != nil {
return nil
}
shaper.Configure(string(jsonConfig))
return shaper
}
// This method is required to implement the Transformer API.
// @param {[]byte} key Key to set, not used by this class.
func (shaper *ProteanShaper) SetKey(key []byte) {
}
// Configure the Transformer with the headers to inject and the headers
// to remove.
func (this *ProteanShaper) Configure(jsonConfig string) {
var proteanConfig ProteanConfig
err := json.Unmarshal([]byte(jsonConfig), &proteanConfig)
if err != nil {
fmt.Println("Encryption shaper requires key parameter")
}
// Required parameters:
// - decompression
// - encryption
// - fragmentation
// - injection
// - headerInjection
this.decompressor = NewDecompressionShaper()
this.encrypter = NewEncryptionShaper()
this.injecter = NewByteSequenceShaper()
this.headerinjecter = NewHeaderShaper()
this.fragmenter = NewFragmentationShaper()
this.decompressor.ConfigureStruct(proteanConfig.decompression)
this.encrypter.ConfigureStruct(proteanConfig.encryption)
this.injecter.ConfigureStruct(proteanConfig.injection)
this.headerinjecter.ConfigureStruct(proteanConfig.headerInjection)
this.fragmenter.ConfigureStruct(proteanConfig.fragmentation)
}
// 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
func (this *ProteanShaper) Transform(buffer []byte) [][]byte {
// This Transform performs the following steps:
// - Generate a new random CHUNK_SIZE-byte IV for every packet
// - Encrypt the packet contents with the random IV and symmetric key
// - Concatenate the IV and encrypted packet contents
source := [][]byte{buffer}
fragmented := flatMap(source, this.fragmenter.Transform)
encrypted := flatMap(fragmented, this.encrypter.Transform)
decompressed := flatMap(encrypted, this.decompressor.Transform)
headerInjected := flatMap(decompressed, this.headerinjecter.Transform)
injected := flatMap(headerInjected, this.injecter.Transform)
return injected
}
// Apply the following Transformations:
// - Discard injected packets
// - Discard injected headers
// - Decrypt with AES
// - Compress with arithmetic coding
// - Attempt defragmentation
func (this *ProteanShaper) Restore(buffer []byte) [][]byte {
// This Restore performs the following steps:
// - Split the first CHUNK_SIZE bytes from the rest of the packet
// The two parts are the IV and the encrypted packet contents
// - Decrypt the encrypted packet contents with the IV and symmetric key
// - Return the decrypted packet contents
source := [][]byte{buffer}
extracted := flatMap(source, this.injecter.Restore)
headerExtracted := flatMap(extracted, this.headerinjecter.Restore)
decompressed := flatMap(headerExtracted, this.decompressor.Restore)
decrypted := flatMap(decompressed, this.encrypter.Restore)
defragmented := flatMap(decrypted, this.fragmenter.Restore)
return defragmented
}
// No-op (we have no state or any resources to Dispose).
func (shaper *ProteanShaper) Dispose() {
}