add wyze support
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
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])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const delta = 0x9e3779b9
|
||||
|
||||
const (
|
||||
StatusDefault byte = 1
|
||||
StatusENR16 byte = 3
|
||||
StatusENR32 byte = 6
|
||||
)
|
||||
|
||||
func XXTEADecrypt(data, key []byte) []byte {
|
||||
if len(data) < 8 || len(key) < 16 {
|
||||
return nil
|
||||
}
|
||||
|
||||
k := make([]uint32, 4)
|
||||
for i := range 4 {
|
||||
k[i] = binary.LittleEndian.Uint32(key[i*4:])
|
||||
}
|
||||
|
||||
n := max(len(data)/4, 2)
|
||||
v := make([]uint32, n)
|
||||
for i := 0; i < len(data)/4; i++ {
|
||||
v[i] = binary.LittleEndian.Uint32(data[i*4:])
|
||||
}
|
||||
|
||||
rounds := 6 + 52/n
|
||||
sum := uint32(rounds) * delta
|
||||
y := v[0]
|
||||
|
||||
for rounds > 0 {
|
||||
e := (sum >> 2) & 3
|
||||
for p := n - 1; p > 0; p-- {
|
||||
z := v[p-1]
|
||||
v[p] -= mx(sum, y, z, p, e, k)
|
||||
y = v[p]
|
||||
}
|
||||
z := v[n-1]
|
||||
v[0] -= mx(sum, y, z, 0, e, k)
|
||||
y = v[0]
|
||||
sum -= delta
|
||||
rounds--
|
||||
}
|
||||
|
||||
result := make([]byte, n*4)
|
||||
for i := range n {
|
||||
binary.LittleEndian.PutUint32(result[i*4:], v[i])
|
||||
}
|
||||
|
||||
return result[:len(data)]
|
||||
}
|
||||
|
||||
func XXTEAEncrypt(data, key []byte) []byte {
|
||||
if len(data) < 8 || len(key) < 16 {
|
||||
return nil
|
||||
}
|
||||
|
||||
k := make([]uint32, 4)
|
||||
for i := range 4 {
|
||||
k[i] = binary.LittleEndian.Uint32(key[i*4:])
|
||||
}
|
||||
|
||||
n := max(len(data)/4, 2)
|
||||
v := make([]uint32, n)
|
||||
for i := 0; i < len(data)/4; i++ {
|
||||
v[i] = binary.LittleEndian.Uint32(data[i*4:])
|
||||
}
|
||||
|
||||
rounds := 6 + 52/n
|
||||
var sum uint32
|
||||
z := v[n-1]
|
||||
|
||||
for rounds > 0 {
|
||||
sum += delta
|
||||
e := (sum >> 2) & 3
|
||||
for p := 0; p < n-1; p++ {
|
||||
y := v[p+1]
|
||||
v[p] += mx(sum, y, z, p, e, k)
|
||||
z = v[p]
|
||||
}
|
||||
y := v[0]
|
||||
v[n-1] += mx(sum, y, z, n-1, e, k)
|
||||
z = v[n-1]
|
||||
rounds--
|
||||
}
|
||||
|
||||
result := make([]byte, n*4)
|
||||
for i := range n {
|
||||
binary.LittleEndian.PutUint32(result[i*4:], v[i])
|
||||
}
|
||||
|
||||
return result[:len(data)]
|
||||
}
|
||||
|
||||
func mx(sum, y, z uint32, p int, e uint32, k []uint32) uint32 {
|
||||
return ((z>>5 ^ y<<2) + (y>>3 ^ z<<4)) ^ ((sum ^ y) + (k[(p&3)^int(e)] ^ z))
|
||||
}
|
||||
|
||||
func GenerateChallengeResponse(challengeBytes []byte, enr string, status byte) []byte {
|
||||
var secretKey []byte
|
||||
|
||||
switch status {
|
||||
case StatusDefault:
|
||||
secretKey = []byte("FFFFFFFFFFFFFFFF")
|
||||
case StatusENR16:
|
||||
if len(enr) >= 16 {
|
||||
secretKey = []byte(enr[:16])
|
||||
} else {
|
||||
secretKey = make([]byte, 16)
|
||||
copy(secretKey, enr)
|
||||
}
|
||||
case StatusENR32:
|
||||
if len(enr) >= 16 {
|
||||
firstKey := []byte(enr[:16])
|
||||
challengeBytes = XXTEADecrypt(challengeBytes, firstKey)
|
||||
}
|
||||
if len(enr) >= 32 {
|
||||
secretKey = []byte(enr[16:32])
|
||||
} else if len(enr) > 16 {
|
||||
secretKey = make([]byte, 16)
|
||||
copy(secretKey, []byte(enr[16:]))
|
||||
} else {
|
||||
secretKey = []byte("FFFFFFFFFFFFFFFF")
|
||||
}
|
||||
default:
|
||||
secretKey = []byte("FFFFFFFFFFFFFFFF")
|
||||
}
|
||||
|
||||
return XXTEADecrypt(challengeBytes, secretKey)
|
||||
}
|
||||
|
||||
func CalculateAuthKey(enr, mac string) []byte {
|
||||
data := enr + strings.ToUpper(mac)
|
||||
hash := sha256.Sum256([]byte(data))
|
||||
b64 := base64.StdEncoding.EncodeToString(hash[:6])
|
||||
b64 = strings.ReplaceAll(b64, "+", "Z")
|
||||
b64 = strings.ReplaceAll(b64, "/", "9")
|
||||
b64 = strings.ReplaceAll(b64, "=", "A")
|
||||
return []byte(b64)
|
||||
}
|
||||
Reference in New Issue
Block a user