1
0
mirror of https://github.com/fumiama/WireGold.git synced 2026-06-10 11:40:30 +08:00
Files
WireGold/gold/link/crypto.go
2024-07-11 22:31:44 +09:00

168 lines
3.8 KiB
Go

package link
import (
"crypto/cipher"
"crypto/rand"
"encoding/binary"
"math/bits"
mrand "math/rand"
)
func (l *Link) randkeyidx() uint8 {
if l.keys[1] == nil {
return 0
}
return uint8(mrand.Intn(32))
}
func mixkeys(k1, k2 []byte) []byte {
if len(k1) != 32 || len(k2) != 32 {
panic("unexpected key len")
}
k := make([]byte, 64)
for i := range k1 {
k1i, k2i := i, 31-i
k1v, k2v := k1[k1i], k2[k2i]
binary.LittleEndian.PutUint16(
k[i*2:(i+1)*2],
expandkeyunit(k1v, k2v),
)
}
return k
}
func expandkeyunit(v1, v2 byte) (v uint16) {
v1s, v2s := uint16(v1), uint16(bits.Reverse8(v2))
for i := 0; i < 8; i++ {
v |= v1s & (1 << (i * 2))
v1s <<= 1
}
for i := 0; i < 8; i++ {
v2s <<= 1
v |= v2s & (2 << (i * 2))
}
return
}
// Encode 使用 xchacha20poly1305 和密钥序列加密
func (l *Link) Encode(teatype uint8, additional uint16, b []byte) (eb []byte) {
if b == nil || teatype >= 32 {
return
}
if l.keys[0] == nil {
eb = make([]byte, len(b))
copy(eb, b)
return
}
aead := l.keys[teatype]
if aead == nil {
return
}
eb = encode(aead, additional, b)
return
}
// Decode 使用 xchacha20poly1305 和密钥序列解密
func (l *Link) Decode(teatype uint8, additional uint16, b []byte) (db []byte) {
if b == nil || teatype >= 32 {
return
}
if l.keys[0] == nil {
db = b
return
}
aead := l.keys[teatype]
if aead == nil {
return
}
db = decode(aead, additional, b)
return
}
// encode 使用 xchacha20poly1305 加密
func encode(aead cipher.AEAD, additional uint16, b []byte) (eb []byte) {
nsz := aead.NonceSize()
// Select a random nonce, and leave capacity for the ciphertext.
nonce := make([]byte, nsz, nsz+len(b)+aead.Overhead())
_, err := rand.Read(nonce)
if err != nil {
return
}
// Encrypt the message and append the ciphertext to the nonce.
var buf [2]byte
binary.LittleEndian.PutUint16(buf[:], additional)
eb = aead.Seal(nonce, nonce, b, buf[:])
return
}
// decode 使用 xchacha20poly1305 解密
func decode(aead cipher.AEAD, additional uint16, b []byte) (db []byte) {
nsz := aead.NonceSize()
if len(b) < nsz { // ciphertext too short
return
}
// Split nonce and ciphertext.
nonce, ciphertext := b[:nsz], b[nsz:]
// Decrypt the message and check it wasn't tampered with.
var buf [2]byte
binary.LittleEndian.PutUint16(buf[:], additional)
db, _ = aead.Open(nil, nonce, ciphertext, buf[:])
return
}
// xorenc 按 8 字节, 以初始 m.mask 循环异或编码 data
func (m *Me) xorenc(data []byte) []byte {
batchsz := len(data) / 8
remain := len(data) % 8
sum := m.mask
if remain > 0 {
var buf [8]byte
p := batchsz * 8
copy(buf[:], data[p:])
sum ^= binary.LittleEndian.Uint64(buf[:])
binary.LittleEndian.PutUint64(buf[:], sum)
copy(data[p:], buf[:])
}
for i := batchsz - 1; i >= 0; i-- {
a := i * 8
b := (i + 1) * 8
sum ^= binary.LittleEndian.Uint64(data[a:b])
binary.LittleEndian.PutUint64(data[a:b], sum)
}
return data
}
// xordec 按 8 字节, 以初始 m.mask 循环异或解码 data
func (m *Me) xordec(data []byte) []byte {
batchsz := len(data) / 8
remain := len(data) % 8
this := uint64(0)
next := uint64(0)
if len(data) >= 8 {
next = binary.LittleEndian.Uint64(data[:8])
}
for i := 0; i < batchsz-1; i++ {
a := i * 8
b := (i + 1) * 8
this = next
next = binary.LittleEndian.Uint64(data[a+8 : b+8])
binary.LittleEndian.PutUint64(data[a:b], this^next)
}
if remain > 0 {
var buf [8]byte
a := (batchsz - 1) * 8
b := batchsz * 8
copy(buf[:], data[b:])
this = next
next = binary.LittleEndian.Uint64(buf[:]) | (m.mask & (uint64(0xffffffff_ffffffff) << (uint64(remain) * 8)))
if batchsz > 0 {
binary.LittleEndian.PutUint64(data[a:b], this^next)
}
binary.LittleEndian.PutUint64(buf[:], next^m.mask)
copy(data[b:], buf[:])
} else {
binary.LittleEndian.PutUint64(data[len(data)-8:], next^m.mask)
}
return data
}