Files
hk4e/pkg/random/hk4e_ec2b.go
2022-11-28 23:36:57 +08:00

178 lines
3.5 KiB
Go

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
}