feat(go): Port full Ananta private server to Go architecture
This commit is contained in:
1 parent
ca2e80f9b7
commit
c73d744649
28 files changed
+3585
-57
No files matched your search
@@ -0,0 +1,114 @@
|
||||
package chacha8
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// NetEase 4229938 UXChaCha8 stream cipher.
|
||||
// Uses custom Sigma constants differing from standard ChaCha.
|
||||
const (
|
||||
Sigma0 uint32 = 0x60707865
|
||||
Sigma1 uint32 = 0x3321646e
|
||||
Sigma2 uint32 = 0x79622d32
|
||||
Sigma3 uint32 = 0x6b206e74
|
||||
)
|
||||
|
||||
type UxChaCha8 struct {
|
||||
state [16]uint32
|
||||
keystream [64]byte
|
||||
keystreamPos int
|
||||
}
|
||||
|
||||
func New(key []byte, nonce []byte) (*UxChaCha8, error) {
|
||||
if len(key) != 32 {
|
||||
return nil, errors.New("UXChaCha8 key must be 32 bytes")
|
||||
}
|
||||
if len(nonce) != 12 {
|
||||
return nil, errors.New("UXChaCha8 nonce must be 12 bytes")
|
||||
}
|
||||
|
||||
c := &UxChaCha8{
|
||||
keystreamPos: 64,
|
||||
}
|
||||
|
||||
c.state[0] = Sigma0
|
||||
c.state[1] = Sigma1
|
||||
c.state[2] = Sigma2
|
||||
c.state[3] = Sigma3
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
c.state[4+i] = binary.LittleEndian.Uint32(key[i*4 : (i+1)*4])
|
||||
}
|
||||
|
||||
c.state[12] = 0
|
||||
c.state[13] = binary.LittleEndian.Uint32(nonce[0:4])
|
||||
c.state[14] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||
c.state[15] = binary.LittleEndian.Uint32(nonce[8:12])
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *UxChaCha8) XorInPlace(data []byte) {
|
||||
offset := 0
|
||||
for offset < len(data) {
|
||||
if c.keystreamPos == 64 {
|
||||
c.generateBlock()
|
||||
c.keystreamPos = 0
|
||||
}
|
||||
|
||||
take := 64 - c.keystreamPos
|
||||
if len(data)-offset < take {
|
||||
take = len(data) - offset
|
||||
}
|
||||
|
||||
for i := 0; i < take; i++ {
|
||||
data[offset+i] ^= c.keystream[c.keystreamPos+i]
|
||||
}
|
||||
|
||||
offset += take
|
||||
c.keystreamPos += take
|
||||
}
|
||||
}
|
||||
|
||||
func (c *UxChaCha8) generateBlock() {
|
||||
var x [16]uint32
|
||||
copy(x[:], c.state[:])
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
quarterRound(&x[0], &x[4], &x[8], &x[12])
|
||||
quarterRound(&x[1], &x[5], &x[9], &x[13])
|
||||
quarterRound(&x[2], &x[6], &x[10], &x[14])
|
||||
quarterRound(&x[3], &x[7], &x[11], &x[15])
|
||||
|
||||
quarterRound(&x[0], &x[5], &x[10], &x[15])
|
||||
quarterRound(&x[1], &x[6], &x[11], &x[12])
|
||||
quarterRound(&x[2], &x[7], &x[8], &x[13])
|
||||
quarterRound(&x[3], &x[4], &x[9], &x[14])
|
||||
}
|
||||
|
||||
for i := 0; i < 16; i++ {
|
||||
binary.LittleEndian.PutUint32(c.keystream[i*4:(i+1)*4], x[i]+c.state[i])
|
||||
}
|
||||
|
||||
c.state[12]++
|
||||
}
|
||||
|
||||
func quarterRound(a, b, c, d *uint32) {
|
||||
*a += *b
|
||||
*d ^= *a
|
||||
*d = bits.RotateLeft32(*d, 16)
|
||||
|
||||
*c += *d
|
||||
*b ^= *c
|
||||
*b = bits.RotateLeft32(*b, 12)
|
||||
|
||||
*a += *b
|
||||
*d ^= *a
|
||||
*d = bits.RotateLeft32(*d, 8)
|
||||
|
||||
*c += *d
|
||||
*b ^= *c
|
||||
*b = bits.RotateLeft32(*b, 7)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package chacha8
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestChaCha8Roundtrip(t *testing.T) {
|
||||
key := make([]byte, 32)
|
||||
for i := range key {
|
||||
key[i] = byte(i + 1)
|
||||
}
|
||||
nonce := make([]byte, 12)
|
||||
for i := range nonce {
|
||||
nonce[i] = byte(i + 0x10)
|
||||
}
|
||||
|
||||
c1, err := New(key, nonce)
|
||||
if err != nil {
|
||||
t.Fatalf("New failed: %v", err)
|
||||
}
|
||||
|
||||
c2, err := New(key, nonce)
|
||||
if err != nil {
|
||||
t.Fatalf("New failed: %v", err)
|
||||
}
|
||||
|
||||
original := []byte("Hello, Ananta NetEase UXChaCha8 stream cipher verification!")
|
||||
data := make([]byte, len(original))
|
||||
copy(data, original)
|
||||
|
||||
c1.XorInPlace(data)
|
||||
if bytes.Equal(data, original) {
|
||||
t.Errorf("Ciphertext equals plaintext")
|
||||
}
|
||||
|
||||
c2.XorInPlace(data)
|
||||
if !bytes.Equal(data, original) {
|
||||
t.Errorf("Decrypted data != original: got %q, want %q", data, original)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user