package random import ( "crypto/rand" "encoding/binary" "fmt" ) type Ec2b struct { key []byte data []byte seed uint64 temp []byte } func LoadEc2bKey(b []byte) (*Ec2b, error) { if len(b) < 4+4+16+4+2048 { return nil, fmt.Errorf("invalid ec2b key") } if string(b[0:4]) != "Ec2b" { return nil, fmt.Errorf("invalid ec2b key") } keyLen := binary.LittleEndian.Uint32(b[4:]) if keyLen != 16 { return nil, fmt.Errorf("invalid ec2b key") } dataLen := binary.LittleEndian.Uint32(b[24:]) if dataLen != 2048 { return nil, fmt.Errorf("invalid ec2b key") } e := &Ec2b{ key: b[8:24], data: b[28 : 28+2048], } e.init() return e, nil } func NewEc2b() *Ec2b { e := &Ec2b{ key: make([]byte, 16), data: make([]byte, 2048), } rand.Read(e.key) rand.Read(e.data) e.init() return e } func (e *Ec2b) init() { k := make([]byte, 16) copy(k[:], e.key) keyScramble(k) e.SetSeed(getSeed(k, e.data)) } func (e *Ec2b) Bytes() []byte { b := make([]byte, 4+4+16+4+2048) copy(b[0:4], []byte("Ec2b")) binary.LittleEndian.PutUint32(b[4:], 16) copy(b[8:], e.key) binary.LittleEndian.PutUint32(b[24:], 2048) copy(b[28:], e.data) return b } func (e *Ec2b) SetSeed(seed uint64) { e.seed = seed r := NewRand64() r.Seed(int64(e.seed)) e.temp = make([]byte, 4096) for i := 0; i < 4096>>3; i++ { binary.LittleEndian.PutUint64(e.temp[i<<3:], r.Uint64()) } } func (e *Ec2b) Seed() uint64 { return e.seed } func (e *Ec2b) Key() []byte { b := make([]byte, 4+4+16+4+2048) copy(b[0:4], []byte("Ec2b")) binary.LittleEndian.PutUint32(b[4:], 16) copy(b[8:], e.key) binary.LittleEndian.PutUint32(b[24:], 2048) copy(b[28:], e.data) return b } func (e *Ec2b) XorKey() []byte { return e.temp } func keyScramble(key []byte) { var roundKeys [11][16]byte for r := 0; r < 11; r++ { for i := 0; i < 16; i++ { for j := 0; j < 16; j++ { idx := (r << 8) + (i << 4) + j roundKeys[r][i] ^= aesXorTable[1][idx] ^ aesXorTable[0][idx] } } } xorRoundKey(key, roundKeys[0][:]) for r := 1; r < 10; r++ { subBytesInv(key) shiftRowsInv(key) mixColsInv(key) xorRoundKey(key, roundKeys[r][:]) } subBytesInv(key) shiftRowsInv(key) xorRoundKey(key, roundKeys[10][:]) for i := 0; i < 16; i++ { key[i] ^= keyXorTable[i] } } func xorRoundKey(key, roundKey []byte) { for i := 0; i < 16; i++ { key[i] ^= roundKey[i] } } func subBytes(key []byte) { for i := 0; i < 16; i++ { key[i] = lookupSbox[key[i]] } } func subBytesInv(key []byte) { for i := 0; i < 16; i++ { key[i] = lookupSboxInv[key[i]] } } func shiftRows(key []byte) { var temp [16]byte copy(temp[:], key[:]) for i := 0; i < 16; i++ { key[i] = temp[shiftRowsTable[i]] } } func shiftRowsInv(key []byte) { var temp [16]byte copy(temp[:], key[:]) for i := 0; i < 16; i++ { key[i] = temp[shiftRowsTableInv[i]] } } func mixColInv(key []byte) { a0, a1, a2, a3 := key[0], key[1], key[2], key[3] key[0] = lookupG14[a0] ^ lookupG9[a3] ^ lookupG13[a2] ^ lookupG11[a1] key[1] = lookupG14[a1] ^ lookupG9[a0] ^ lookupG13[a3] ^ lookupG11[a2] key[2] = lookupG14[a2] ^ lookupG9[a1] ^ lookupG13[a0] ^ lookupG11[a3] key[3] = lookupG14[a3] ^ lookupG9[a2] ^ lookupG13[a1] ^ lookupG11[a0] } func mixColsInv(key []byte) { mixColInv(key[0:]) mixColInv(key[4:]) mixColInv(key[8:]) mixColInv(key[12:]) } func getSeed(key, data []byte) uint64 { v := ^uint64(0xCEAC3B5A867837AC) v ^= binary.LittleEndian.Uint64(key[0:]) v ^= binary.LittleEndian.Uint64(key[8:]) for i := 0; i < len(data)>>3; i++ { v ^= binary.LittleEndian.Uint64(data[i<<3:]) } return v }