github.com/metacubex/mihomo@v1.18.5/common/net/websocket.go (about) 1 package net 2 3 import ( 4 "encoding/binary" 5 "math/bits" 6 ) 7 8 // kanged from https://github.com/nhooyr/websocket/blob/master/frame.go 9 // License: MIT 10 11 // MaskWebSocket applies the WebSocket masking algorithm to p 12 // with the given key. 13 // See https://tools.ietf.org/html/rfc6455#section-5.3 14 // 15 // The returned value is the correctly rotated key to 16 // to continue to mask/unmask the message. 17 // 18 // It is optimized for LittleEndian and expects the key 19 // to be in little endian. 20 // 21 // See https://github.com/golang/go/issues/31586 22 func MaskWebSocket(key uint32, b []byte) uint32 { 23 if len(b) >= 8 { 24 key64 := uint64(key)<<32 | uint64(key) 25 26 // At some point in the future we can clean these unrolled loops up. 27 // See https://github.com/golang/go/issues/31586#issuecomment-487436401 28 29 // Then we xor until b is less than 128 bytes. 30 for len(b) >= 128 { 31 v := binary.LittleEndian.Uint64(b) 32 binary.LittleEndian.PutUint64(b, v^key64) 33 v = binary.LittleEndian.Uint64(b[8:16]) 34 binary.LittleEndian.PutUint64(b[8:16], v^key64) 35 v = binary.LittleEndian.Uint64(b[16:24]) 36 binary.LittleEndian.PutUint64(b[16:24], v^key64) 37 v = binary.LittleEndian.Uint64(b[24:32]) 38 binary.LittleEndian.PutUint64(b[24:32], v^key64) 39 v = binary.LittleEndian.Uint64(b[32:40]) 40 binary.LittleEndian.PutUint64(b[32:40], v^key64) 41 v = binary.LittleEndian.Uint64(b[40:48]) 42 binary.LittleEndian.PutUint64(b[40:48], v^key64) 43 v = binary.LittleEndian.Uint64(b[48:56]) 44 binary.LittleEndian.PutUint64(b[48:56], v^key64) 45 v = binary.LittleEndian.Uint64(b[56:64]) 46 binary.LittleEndian.PutUint64(b[56:64], v^key64) 47 v = binary.LittleEndian.Uint64(b[64:72]) 48 binary.LittleEndian.PutUint64(b[64:72], v^key64) 49 v = binary.LittleEndian.Uint64(b[72:80]) 50 binary.LittleEndian.PutUint64(b[72:80], v^key64) 51 v = binary.LittleEndian.Uint64(b[80:88]) 52 binary.LittleEndian.PutUint64(b[80:88], v^key64) 53 v = binary.LittleEndian.Uint64(b[88:96]) 54 binary.LittleEndian.PutUint64(b[88:96], v^key64) 55 v = binary.LittleEndian.Uint64(b[96:104]) 56 binary.LittleEndian.PutUint64(b[96:104], v^key64) 57 v = binary.LittleEndian.Uint64(b[104:112]) 58 binary.LittleEndian.PutUint64(b[104:112], v^key64) 59 v = binary.LittleEndian.Uint64(b[112:120]) 60 binary.LittleEndian.PutUint64(b[112:120], v^key64) 61 v = binary.LittleEndian.Uint64(b[120:128]) 62 binary.LittleEndian.PutUint64(b[120:128], v^key64) 63 b = b[128:] 64 } 65 66 // Then we xor until b is less than 64 bytes. 67 for len(b) >= 64 { 68 v := binary.LittleEndian.Uint64(b) 69 binary.LittleEndian.PutUint64(b, v^key64) 70 v = binary.LittleEndian.Uint64(b[8:16]) 71 binary.LittleEndian.PutUint64(b[8:16], v^key64) 72 v = binary.LittleEndian.Uint64(b[16:24]) 73 binary.LittleEndian.PutUint64(b[16:24], v^key64) 74 v = binary.LittleEndian.Uint64(b[24:32]) 75 binary.LittleEndian.PutUint64(b[24:32], v^key64) 76 v = binary.LittleEndian.Uint64(b[32:40]) 77 binary.LittleEndian.PutUint64(b[32:40], v^key64) 78 v = binary.LittleEndian.Uint64(b[40:48]) 79 binary.LittleEndian.PutUint64(b[40:48], v^key64) 80 v = binary.LittleEndian.Uint64(b[48:56]) 81 binary.LittleEndian.PutUint64(b[48:56], v^key64) 82 v = binary.LittleEndian.Uint64(b[56:64]) 83 binary.LittleEndian.PutUint64(b[56:64], v^key64) 84 b = b[64:] 85 } 86 87 // Then we xor until b is less than 32 bytes. 88 for len(b) >= 32 { 89 v := binary.LittleEndian.Uint64(b) 90 binary.LittleEndian.PutUint64(b, v^key64) 91 v = binary.LittleEndian.Uint64(b[8:16]) 92 binary.LittleEndian.PutUint64(b[8:16], v^key64) 93 v = binary.LittleEndian.Uint64(b[16:24]) 94 binary.LittleEndian.PutUint64(b[16:24], v^key64) 95 v = binary.LittleEndian.Uint64(b[24:32]) 96 binary.LittleEndian.PutUint64(b[24:32], v^key64) 97 b = b[32:] 98 } 99 100 // Then we xor until b is less than 16 bytes. 101 for len(b) >= 16 { 102 v := binary.LittleEndian.Uint64(b) 103 binary.LittleEndian.PutUint64(b, v^key64) 104 v = binary.LittleEndian.Uint64(b[8:16]) 105 binary.LittleEndian.PutUint64(b[8:16], v^key64) 106 b = b[16:] 107 } 108 109 // Then we xor until b is less than 8 bytes. 110 for len(b) >= 8 { 111 v := binary.LittleEndian.Uint64(b) 112 binary.LittleEndian.PutUint64(b, v^key64) 113 b = b[8:] 114 } 115 } 116 117 // Then we xor until b is less than 4 bytes. 118 for len(b) >= 4 { 119 v := binary.LittleEndian.Uint32(b) 120 binary.LittleEndian.PutUint32(b, v^key) 121 b = b[4:] 122 } 123 124 // xor remaining bytes. 125 for i := range b { 126 b[i] ^= byte(key) 127 key = bits.RotateLeft32(key, -8) 128 } 129 130 return key 131 }