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  }