mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2026-04-22 15:47:06 +08:00
144 lines
3.4 KiB
Go
144 lines
3.4 KiB
Go
package crypto
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"math/bits"
|
|
)
|
|
|
|
const charlie = "Charlie is the designer of P2P!!"
|
|
|
|
func TransCodePartial(src []byte) []byte {
|
|
n := len(src)
|
|
tmp := make([]byte, n)
|
|
dst := bytes.Clone(src)
|
|
src16, tmp16, dst16 := src, tmp, dst
|
|
|
|
for ; n >= 16; n -= 16 {
|
|
for i := 0; i < 16; i += 4 {
|
|
x := binary.LittleEndian.Uint32(src16[i:])
|
|
binary.LittleEndian.PutUint32(tmp16[i:], bits.RotateLeft32(x, -i-1))
|
|
}
|
|
for i := range 16 {
|
|
dst16[i] = tmp16[i] ^ charlie[i]
|
|
}
|
|
swap(dst16, tmp16, 16)
|
|
for i := 0; i < 16; i += 4 {
|
|
x := binary.LittleEndian.Uint32(tmp16[i:])
|
|
binary.LittleEndian.PutUint32(dst16[i:], bits.RotateLeft32(x, -i-3))
|
|
}
|
|
tmp16, dst16, src16 = tmp16[16:], dst16[16:], src16[16:]
|
|
}
|
|
|
|
for i := 0; i < n; i++ {
|
|
tmp16[i] = src16[i] ^ charlie[i]
|
|
}
|
|
swap(tmp16, dst16, n)
|
|
return dst
|
|
}
|
|
|
|
func ReverseTransCodePartial(src []byte) []byte {
|
|
n := len(src)
|
|
tmp := make([]byte, n)
|
|
dst := bytes.Clone(src)
|
|
src16, tmp16, dst16 := src, tmp, dst
|
|
|
|
for ; n >= 16; n -= 16 {
|
|
for i := 0; i < 16; i += 4 {
|
|
x := binary.LittleEndian.Uint32(src16[i:])
|
|
binary.LittleEndian.PutUint32(tmp16[i:], bits.RotateLeft32(x, i+3))
|
|
}
|
|
swap(tmp16, dst16, 16)
|
|
for i := range 16 {
|
|
tmp16[i] = dst16[i] ^ charlie[i]
|
|
}
|
|
for i := 0; i < 16; i += 4 {
|
|
x := binary.LittleEndian.Uint32(tmp16[i:])
|
|
binary.LittleEndian.PutUint32(dst16[i:], bits.RotateLeft32(x, i+1))
|
|
}
|
|
tmp16, dst16, src16 = tmp16[16:], dst16[16:], src16[16:]
|
|
}
|
|
|
|
swap(src16, tmp16, n)
|
|
for i := 0; i < n; i++ {
|
|
dst16[i] = tmp16[i] ^ charlie[i]
|
|
}
|
|
return dst
|
|
}
|
|
|
|
func TransCodeBlob(src []byte) []byte {
|
|
if len(src) < 16 {
|
|
return TransCodePartial(src)
|
|
}
|
|
|
|
dst := make([]byte, len(src))
|
|
header := TransCodePartial(src[:16])
|
|
copy(dst, header)
|
|
|
|
if len(src) > 16 {
|
|
if src[3]&1 != 0 { // Partial encryption
|
|
remaining := len(src) - 16
|
|
encryptLen := min(remaining, 48)
|
|
if encryptLen > 0 {
|
|
encrypted := TransCodePartial(src[16 : 16+encryptLen])
|
|
copy(dst[16:], encrypted)
|
|
}
|
|
if remaining > 48 {
|
|
copy(dst[64:], src[64:])
|
|
}
|
|
} else { // Full encryption
|
|
encrypted := TransCodePartial(src[16:])
|
|
copy(dst[16:], encrypted)
|
|
}
|
|
}
|
|
return dst
|
|
}
|
|
|
|
func ReverseTransCodeBlob(src []byte) []byte {
|
|
if len(src) < 16 {
|
|
return ReverseTransCodePartial(src)
|
|
}
|
|
|
|
dst := make([]byte, len(src))
|
|
header := ReverseTransCodePartial(src[:16])
|
|
copy(dst, header)
|
|
|
|
if len(src) > 16 {
|
|
if dst[3]&1 != 0 { // Partial encryption (check decrypted header)
|
|
remaining := len(src) - 16
|
|
decryptLen := min(remaining, 48)
|
|
if decryptLen > 0 {
|
|
decrypted := ReverseTransCodePartial(src[16 : 16+decryptLen])
|
|
copy(dst[16:], decrypted)
|
|
}
|
|
if remaining > 48 {
|
|
copy(dst[64:], src[64:])
|
|
}
|
|
} else { // Full decryption
|
|
decrypted := ReverseTransCodePartial(src[16:])
|
|
copy(dst[16:], decrypted)
|
|
}
|
|
}
|
|
return dst
|
|
}
|
|
|
|
func RandRead(b []byte) {
|
|
_, _ = rand.Read(b)
|
|
}
|
|
|
|
func swap(src, dst []byte, n int) {
|
|
switch n {
|
|
case 8:
|
|
dst[0], dst[1], dst[2], dst[3] = src[7], src[4], src[3], src[2]
|
|
dst[4], dst[5], dst[6], dst[7] = src[1], src[6], src[5], src[0]
|
|
case 16:
|
|
dst[0], dst[1], dst[2], dst[3] = src[11], src[9], src[8], src[15]
|
|
dst[4], dst[5], dst[6], dst[7] = src[13], src[10], src[12], src[14]
|
|
dst[8], dst[9], dst[10], dst[11] = src[2], src[1], src[5], src[0]
|
|
dst[12], dst[13], dst[14], dst[15] = src[6], src[4], src[7], src[3]
|
|
default:
|
|
copy(dst, src[:n])
|
|
}
|
|
}
|