Cipher applies XOR cipher to the payload using mask. Offset is used to cipher chunked data (e.g. in io.Reader implementations). To convert masked data into unmasked data, or vice versa, the following algorithm is applied. The same algorithm applies regardless of the direction of the translation, e
(payload []byte, mask [4]byte, offset int)
| 12 | // direction of the translation, e.g., the same steps are applied to |
| 13 | // mask the data as to unmask the data. |
| 14 | func Cipher(payload []byte, mask [4]byte, offset int) { |
| 15 | n := len(payload) |
| 16 | if n < 8 { |
| 17 | for i := 0; i < n; i++ { |
| 18 | payload[i] ^= mask[(offset+i)%4] |
| 19 | } |
| 20 | return |
| 21 | } |
| 22 | |
| 23 | // Calculate position in mask due to previously processed bytes number. |
| 24 | mpos := offset % 4 |
| 25 | // Count number of bytes will processed one by one from the beginning of payload. |
| 26 | ln := remain[mpos] |
| 27 | // Count number of bytes will processed one by one from the end of payload. |
| 28 | // This is done to process payload by 16 bytes in each iteration of main loop. |
| 29 | rn := (n - ln) % 16 |
| 30 | |
| 31 | for i := 0; i < ln; i++ { |
| 32 | payload[i] ^= mask[(mpos+i)%4] |
| 33 | } |
| 34 | for i := n - rn; i < n; i++ { |
| 35 | payload[i] ^= mask[(mpos+i)%4] |
| 36 | } |
| 37 | |
| 38 | // NOTE: we use here binary.LittleEndian regardless of what is real |
| 39 | // endianness on machine is. To do so, we have to use binary.LittleEndian in |
| 40 | // the masking loop below as well. |
| 41 | var ( |
| 42 | m = binary.LittleEndian.Uint32(mask[:]) |
| 43 | m2 = uint64(m)<<32 | uint64(m) |
| 44 | ) |
| 45 | // Skip already processed right part. |
| 46 | // Get number of uint64 parts remaining to process. |
| 47 | n = (n - ln - rn) >> 4 |
| 48 | j := ln |
| 49 | for i := 0; i < n; i++ { |
| 50 | chunk := payload[j : j+16] |
| 51 | p := binary.LittleEndian.Uint64(chunk) ^ m2 |
| 52 | p2 := binary.LittleEndian.Uint64(chunk[8:]) ^ m2 |
| 53 | binary.LittleEndian.PutUint64(chunk, p) |
| 54 | binary.LittleEndian.PutUint64(chunk[8:], p2) |
| 55 | j += 16 |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | // remain maps position in masking key [0,4) to number |
| 60 | // of bytes that need to be processed manually inside Cipher(). |
no outgoing calls
searching dependent graphs…