/* SPDX-License-Identifier: MIT * * Phobos */ // Package cobf binds the shared wg-obfuscator C sources in // src/phobos-obfuscator. It is the only implementation of the Phobos wire // protocol in this tree; there is deliberately no Go port to drift from. package cobf /* #cgo CFLAGS: -I${SRCDIR}/../../../src/phobos-obfuscator #cgo windows LDFLAGS: -lws2_32 #include "bridge.h" */ import "C" import "unsafe" func keyPtr(key []byte) *C.char { return (*C.char)(unsafe.Pointer(unsafe.SliceData(key))) } // Encode obfuscates buffer[:length] in place and returns the new length, // which may exceed length when the C side appends dummy padding. func Encode(buffer []byte, length int, key []byte, maxDummyData, obfuscateBytes int) int { return int(C.cobf_encode((*C.uint8_t)(unsafe.SliceData(buffer)), C.int(length), keyPtr(key), C.int(len(key)), C.int(maxDummyData), C.int(obfuscateBytes))) } // Decode deobfuscates buffer[:length] in place and returns the payload length. // version reports the protocol version detected in the packet header. func Decode(buffer []byte, length int, key []byte, obfuscateBytes int) (n int, version uint8) { var v C.uint8_t n = int(C.cobf_decode((*C.uint8_t)(unsafe.SliceData(buffer)), C.int(length), keyPtr(key), C.int(len(key)), C.int(obfuscateBytes), &v)) return n, uint8(v) } // XOR applies the keystream to buffer[:length] in place. Encode and Decode // already do this; it is exported for the golden-vector regression tests. func XOR(buffer []byte, length int, key []byte) { C.cobf_xor((*C.uint8_t)(unsafe.SliceData(buffer)), C.int(length), keyPtr(key), C.int(len(key))) } // StreamCipher is the continuous keystream used for SOCKS5 TCP streams. Its // state lives in Go memory: the C struct holds no pointers, so it needs no // manual lifecycle. type StreamCipher struct { state []uint64 } func NewStreamCipher(key []byte) *StreamCipher { words := (int(C.cobf_stream_size()) + 7) / 8 s := &StreamCipher{state: make([]uint64, words)} C.cobf_stream_init(unsafe.Pointer(unsafe.SliceData(s.state)), keyPtr(key), C.int(len(key))) return s } func (s *StreamCipher) Apply(buffer []byte) { if len(buffer) == 0 { return } C.cobf_stream_apply(unsafe.Pointer(unsafe.SliceData(s.state)), (*C.uint8_t)(unsafe.SliceData(buffer)), C.int(len(buffer))) }