utils.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. package tapdance
  2. import (
  3. "bytes"
  4. "crypto/aes"
  5. "crypto/cipher"
  6. "crypto/rand"
  7. "crypto/sha256"
  8. "encoding/binary"
  9. "errors"
  10. "fmt"
  11. mrand "math/rand"
  12. "net"
  13. "strconv"
  14. "strings"
  15. "time"
  16. "github.com/refraction-networking/gotapdance/ed25519/extra25519"
  17. "golang.org/x/crypto/curve25519"
  18. )
  19. // The key argument should be the AES key, either 16 or 32 bytes
  20. // to select AES-128 or AES-256.
  21. func aesGcmEncrypt(plaintext []byte, key []byte, iv []byte) ([]byte, error) {
  22. block, err := aes.NewCipher(key)
  23. if err != nil {
  24. return nil, err
  25. }
  26. aesGcmCipher, err := cipher.NewGCM(block)
  27. if err != nil {
  28. return nil, err
  29. }
  30. return aesGcmCipher.Seal(nil, iv, plaintext, nil), nil
  31. }
  32. // Tries to get crypto random int in range [min, max]
  33. // In case of crypto failure -- return insecure pseudorandom
  34. func getRandInt(min int, max int) int {
  35. // I can't believe Golang is making me do that
  36. // Flashback to awful C/C++ libraries
  37. diff := max - min
  38. if diff < 0 {
  39. Logger().Warningf("getRandInt(): max is less than min")
  40. min = max
  41. diff *= -1
  42. } else if diff == 0 {
  43. return min
  44. }
  45. var v int64
  46. err := binary.Read(rand.Reader, binary.LittleEndian, &v)
  47. if v < 0 {
  48. v *= -1
  49. }
  50. if err != nil {
  51. Logger().Warningf("Unable to securely get getRandInt(): " + err.Error())
  52. v = mrand.Int63()
  53. }
  54. return min + int(v%int64(diff+1))
  55. }
  56. // returns random duration between min and max in milliseconds
  57. func getRandomDuration(min int, max int) time.Duration {
  58. return time.Millisecond * time.Duration(getRandInt(min, max))
  59. }
  60. // Get padding of length [minLen, maxLen).
  61. // Distributed in pseudogaussian style.
  62. // Padded using symbol '#'. Known plaintext attacks, anyone?
  63. func getRandPadding(minLen int, maxLen int, smoothness int) string {
  64. paddingLen := 0
  65. for j := 0; j < smoothness; j++ {
  66. paddingLen += getRandInt(minLen, maxLen)
  67. }
  68. paddingLen = paddingLen / smoothness
  69. return strings.Repeat("#", paddingLen)
  70. }
  71. func getRandString(length int) string {
  72. const alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  73. randString := make([]byte, length)
  74. for i := range randString {
  75. randString[i] = alphabet[getRandInt(0, len(alphabet)-1)]
  76. }
  77. return string(randString)
  78. }
  79. type tapdanceSharedKeys struct {
  80. FspKey, FspIv, VspKey, VspIv, NewMasterSecret, ConjureSeed []byte
  81. }
  82. func getMsgWithHeader(msgType msgType, msgBytes []byte) []byte {
  83. if len(msgBytes) == 0 {
  84. return nil
  85. }
  86. bufSend := new(bytes.Buffer)
  87. var err error
  88. switch msgType {
  89. case msgProtobuf:
  90. if len(msgBytes) <= int(maxInt16) {
  91. bufSend.Grow(2 + len(msgBytes)) // to avoid double allocation
  92. err = binary.Write(bufSend, binary.BigEndian, int16(len(msgBytes)))
  93. } else {
  94. bufSend.Grow(2 + 4 + len(msgBytes)) // to avoid double allocation
  95. bufSend.Write([]byte{0, 0})
  96. err = binary.Write(bufSend, binary.BigEndian, int32(len(msgBytes)))
  97. }
  98. case msgRawData:
  99. err = binary.Write(bufSend, binary.BigEndian, int16(-len(msgBytes)))
  100. default:
  101. panic("getMsgWithHeader() called with msgType: " + strconv.Itoa(int(msgType)))
  102. }
  103. if err != nil {
  104. // shouldn't ever happen
  105. Logger().Errorln("getMsgWithHeader() failed with error: ", err)
  106. Logger().Errorln("msgType ", msgType)
  107. Logger().Errorln("msgBytes ", msgBytes)
  108. }
  109. bufSend.Write(msgBytes)
  110. return bufSend.Bytes()
  111. }
  112. func uint16toInt16(i uint16) int16 {
  113. pos := int16(i & 32767)
  114. neg := int16(0)
  115. if i&32768 != 0 {
  116. neg = int16(-32768)
  117. }
  118. return pos + neg
  119. }
  120. // generates HTTP request, that is ready to have tag prepended to it
  121. func generateHTTPRequestBeginning(decoyHostname string) []byte {
  122. sharedHeaders := `Host: ` + decoyHostname +
  123. "\nUser-Agent: TapDance/1.2 (+https://refraction.network/info)"
  124. httpTag := fmt.Sprintf(`GET / HTTP/1.1
  125. %s
  126. X-Ignore: %s`, sharedHeaders, getRandPadding(7, maxInt(612-len(sharedHeaders), 7), 10))
  127. return []byte(strings.Replace(httpTag, "\n", "\r\n", -1))
  128. }
  129. func reverseEncrypt(ciphertext []byte, keyStream []byte) []byte {
  130. var plaintext string
  131. // our plaintext can be antyhing where x & 0xc0 == 0x40
  132. // i.e. 64-127 in ascii (@, A-Z, [\]^_`, a-z, {|}~ DEL)
  133. // This means that we are allowed to choose the last 6 bits
  134. // of each byte in the ciphertext arbitrarily; the upper 2
  135. // bits will have to be 01, so that our plaintext ends up
  136. // in the desired range.
  137. var ka, kb, kc, kd byte // key stream bytes
  138. var ca, cb, cc, cd byte // ciphertext bytes
  139. var pa, pb, pc, pd byte // plaintext bytes
  140. var sa, sb, sc byte // secret bytes
  141. var tagIdx, keystreamIdx int
  142. for tagIdx < len(ciphertext) {
  143. ka = keyStream[keystreamIdx]
  144. kb = keyStream[keystreamIdx+1]
  145. kc = keyStream[keystreamIdx+2]
  146. kd = keyStream[keystreamIdx+3]
  147. keystreamIdx += 4
  148. // read 3 bytes
  149. sa = ciphertext[tagIdx]
  150. sb = ciphertext[tagIdx+1]
  151. sc = ciphertext[tagIdx+2]
  152. tagIdx += 3
  153. // figure out what plaintext needs to be in base64 encode
  154. ca = (ka & 0xc0) | ((sa & 0xfc) >> 2) // 6 bits sa
  155. cb = (kb & 0xc0) | (((sa & 0x03) << 4) | ((sb & 0xf0) >> 4)) // 2 bits sa, 4 bits sb
  156. cc = (kc & 0xc0) | (((sb & 0x0f) << 2) | ((sc & 0xc0) >> 6)) // 4 bits sb, 2 bits sc
  157. cd = (kd & 0xc0) | (sc & 0x3f) // 6 bits sc
  158. // Xor with key_stream, and add on 0x40 so it's in range of allowed
  159. pa = (ca ^ ka) + 0x40
  160. pb = (cb ^ kb) + 0x40
  161. pc = (cc ^ kc) + 0x40
  162. pd = (cd ^ kd) + 0x40
  163. plaintext += string(pa)
  164. plaintext += string(pb)
  165. plaintext += string(pc)
  166. plaintext += string(pd)
  167. }
  168. return []byte(plaintext)
  169. }
  170. func minInt(a, b int) int {
  171. if a > b {
  172. return b
  173. }
  174. return a
  175. }
  176. func maxInt(a, b int) int {
  177. if a > b {
  178. return a
  179. }
  180. return b
  181. }
  182. // Converts provided duration to raw milliseconds.
  183. // Returns a pointer to u32, because protobuf wants pointers.
  184. // Max valid input duration (that fits into uint32): 49.71 days.
  185. func durationToU32ptrMs(d time.Duration) *uint32 {
  186. i := uint32(d.Nanoseconds() / int64(time.Millisecond))
  187. return &i
  188. }
  189. func readAndClose(c net.Conn, readDeadline time.Duration) {
  190. tinyBuf := []byte{0}
  191. c.SetReadDeadline(time.Now().Add(readDeadline))
  192. c.Read(tinyBuf)
  193. c.Close()
  194. }
  195. func errIsTimeout(err error) bool {
  196. if err != nil {
  197. if strings.Contains(err.Error(), ": i/o timeout") || // client timed out
  198. err.Error() == "EOF" { // decoy timed out
  199. return true
  200. }
  201. }
  202. return false
  203. }
  204. // obfuscateTagAndProtobuf() generates key-pair and combines it /w stationPubkey to generate
  205. // sharedSecret. Client will use Eligator to find and send uniformly random representative for its
  206. // public key (and avoid sending it directly over the wire, as points on ellyptic curve are
  207. // distinguishable)
  208. // Then the sharedSecret will be used to encrypt stegoPayload and protobuf slices:
  209. // - stegoPayload is encrypted with AES-GCM KEY=sharedSecret[0:16], IV=sharedSecret[16:28]
  210. // - protobuf is encrypted with AES-GCM KEY=sharedSecret[0:16], IV={new random IV}, that will be
  211. // prepended to encryptedProtobuf and eventually sent out together
  212. // Returns
  213. // - tag(concatenated representative and encrypted stegoPayload),
  214. // - encryptedProtobuf(concatenated 12 byte IV + encrypted protobuf)
  215. // - error
  216. func obfuscateTagAndProtobuf(stegoPayload []byte, protobuf []byte, stationPubkey []byte) ([]byte, []byte, error) {
  217. if len(stationPubkey) != 32 {
  218. return nil, nil, errors.New("Unexpected station pubkey length. Expected: 32." +
  219. " Received: " + strconv.Itoa(len(stationPubkey)) + ".")
  220. }
  221. var sharedSecret, clientPrivate, clientPublic, representative [32]byte
  222. for ok := false; ok != true; {
  223. var sliceKeyPrivate []byte = clientPrivate[:]
  224. _, err := rand.Read(sliceKeyPrivate)
  225. if err != nil {
  226. return nil, nil, err
  227. }
  228. ok = extra25519.ScalarBaseMult(&clientPublic, &representative, &clientPrivate)
  229. }
  230. var stationPubkeyByte32 [32]byte
  231. copy(stationPubkeyByte32[:], stationPubkey)
  232. curve25519.ScalarMult(&sharedSecret, &clientPrivate, &stationPubkeyByte32)
  233. // extra25519.ScalarBaseMult does not randomize most significant bit(sign of y_coord?)
  234. // Other implementations of elligator may have up to 2 non-random bits.
  235. // Here we randomize the bit, expecting it to be flipped back to 0 on station
  236. randByte := make([]byte, 1)
  237. _, err := rand.Read(randByte)
  238. if err != nil {
  239. return nil, nil, err
  240. }
  241. representative[31] |= (0x80 & randByte[0])
  242. tagBuf := new(bytes.Buffer) // What we have to encrypt with the shared secret using AES
  243. tagBuf.Write(representative[:])
  244. stationPubkeyHash := sha256.Sum256(sharedSecret[:])
  245. aesKey := stationPubkeyHash[:16]
  246. aesIvTag := stationPubkeyHash[16:28] // 12 bytes for stegoPayload nonce
  247. encryptedStegoPayload, err := aesGcmEncrypt(stegoPayload, aesKey, aesIvTag)
  248. if err != nil {
  249. return nil, nil, err
  250. }
  251. tagBuf.Write(encryptedStegoPayload)
  252. tag := tagBuf.Bytes()
  253. if len(protobuf) == 0 {
  254. return tag, nil, err
  255. }
  256. // probably could have used all zeros as IV here, but better to err on safe side
  257. aesIvProtobuf := make([]byte, 12)
  258. _, err = rand.Read(aesIvProtobuf)
  259. if err != nil {
  260. return nil, nil, err
  261. }
  262. encryptedProtobuf, err := aesGcmEncrypt(protobuf, aesKey, aesIvProtobuf)
  263. return tag, append(aesIvProtobuf, encryptedProtobuf...), err
  264. }