basic feature set

This commit is contained in:
Matthias Fulz 2022-06-26 23:58:14 +02:00
parent 4a1c86d80d
commit 473457ebb1
3 changed files with 204 additions and 114 deletions

View File

@ -3,11 +3,20 @@ package qmkenc
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"math/rand"
"time"
) )
var magicHeader = []byte{0x03, 0xFF} var magicHeader = []byte{0x03, 0xFF}
type QEncCmd byte type QEncCmd byte
type QEncInfoFct func(string)
type QEncEndFct func()
type QEncErrFct func(error)
var QEncInfoHandler QEncInfoFct
var QEncEndHandler QEncEndFct
var QEncErrHandler QEncErrFct
const ( const (
QENC_CMD_RESET QEncCmd = 0x00 QENC_CMD_RESET QEncCmd = 0x00
@ -24,8 +33,49 @@ const (
QENC_CMD_SET_KEYS QEncCmd = 0x0B QENC_CMD_SET_KEYS QEncCmd = 0x0B
QENC_CMD_GET_CFG QEncCmd = 0x0C QENC_CMD_GET_CFG QEncCmd = 0x0C
QENC_CMD_INITIALIZE QEncCmd = 0x0D QENC_CMD_INITIALIZE QEncCmd = 0x0D
QENC_CMD_NONE QEncCmd = 0x0E
QENC_CMD_SET_BUFFER QEncCmd = 0x0F
) )
func (e QEncCmd) String() string {
switch e {
case QENC_CMD_RESET:
return "Reset cmd"
case QENC_CMD_ENCRYPT:
return "Encrypt cmd"
case QENC_CMD_DECRYPT:
return "Decrypt cmd"
case QENC_CMD_MORE_DATA:
return "More data cmd"
case QENC_CMD_UNLOCK:
return "Unlock cmd"
case QENC_CMD_LOCK:
return "Lock cmd"
case QENC_CMD_SET_CFG:
return "Set cfg cmd"
case QENC_CMD_GET_MODE:
return "Get mode cmd"
case QENC_CMD_GET_BUFFER:
return "Get buffer cmd"
case QENC_CMD_GET_KEYS:
return "Get keys cmd"
case QENC_CMD_GET_BUFFSIZE:
return "Get buffsize cmd"
case QENC_CMD_SET_KEYS:
return "Set keys cmd"
case QENC_CMD_GET_CFG:
return "Get cfg cmd"
case QENC_CMD_INITIALIZE:
return "Initialize cmd"
case QENC_CMD_NONE:
return "None cmd"
case QENC_CMD_SET_BUFFER:
return "Set buffer cmd"
default:
return "Unknown cmd"
}
}
type QEncMode byte type QEncMode byte
const ( const (
@ -35,6 +85,21 @@ const (
QENC_MODE_INIT QEncMode = 0x03 QENC_MODE_INIT QEncMode = 0x03
) )
func (e QEncMode) String() string {
switch e {
case QENC_MODE_CLOSED:
return "Closed"
case QENC_MODE_OPEN:
return "Open"
case QENC_MODE_LOAD:
return "Load"
case QENC_MODE_INIT:
return "Init"
default:
return "Unknown"
}
}
type QEncSubMode byte type QEncSubMode byte
const ( const (
@ -44,6 +109,21 @@ const (
QENC_SUB_MODE_VERIFY_PASSWORD QEncSubMode = 0x03 QENC_SUB_MODE_VERIFY_PASSWORD QEncSubMode = 0x03
) )
func (e QEncSubMode) String() string {
switch e {
case QENC_SUB_MODE_NONE:
return "None"
case QENC_SUB_MODE_SEED:
return "Seed"
case QENC_SUB_MODE_PASSWORD:
return "Password"
case QENC_SUB_MODE_VERIFY_PASSWORD:
return "Verify Password"
default:
return "Unknown"
}
}
type QEncCfg byte type QEncCfg byte
const ( const (
@ -91,71 +171,55 @@ func (q *QCfg) Initialized() bool {
} }
func QCmdReset(dev *QEncDevice) (err error) { func QCmdReset(dev *QEncDevice) (err error) {
buf, err := initBuffer(dev, QENC_CMD_RESET) rand.Seed(time.Now().UnixNano())
if err != nil { id := rand.Uint32()
return err _, err = sendDataWrapper(dev, []byte{}, QENC_CMD_RESET, id)
}
_, err = dev.SendBuffer(buf)
return err return err
} }
func QCmdUnlock(dev *QEncDevice) (err error) { func QCmdUnlock(dev *QEncDevice) (err error) {
buf, err := initBuffer(dev, QENC_CMD_UNLOCK) rand.Seed(time.Now().UnixNano())
if err != nil { id := rand.Uint32()
return err _, err = sendDataWrapper(dev, []byte{}, QENC_CMD_UNLOCK, id)
}
_, err = dev.SendBuffer(buf)
return err return err
} }
func QCmdLock(dev *QEncDevice) (err error) { func QCmdLock(dev *QEncDevice) (err error) {
buf, err := initBuffer(dev, QENC_CMD_LOCK) rand.Seed(time.Now().UnixNano())
if err != nil { id := rand.Uint32()
return err _, err = sendDataWrapper(dev, []byte{}, QENC_CMD_LOCK, id)
}
_, err = dev.SendBuffer(buf)
return err return err
} }
func QCmdInitialize(dev *QEncDevice) (err error) { func QCmdInitialize(dev *QEncDevice) (err error) {
buf, err := initBuffer(dev, QENC_CMD_INITIALIZE) rand.Seed(time.Now().UnixNano())
if err != nil { id := rand.Uint32()
return err _, err = sendDataWrapper(dev, []byte{}, QENC_CMD_INITIALIZE, id)
}
_, err = dev.SendBuffer(buf)
return err return err
} }
func QCmdEncrypt(dev *QEncDevice, data []byte) (err error) { func QCmdEncrypt(dev *QEncDevice, data []byte) (ret []byte, err error) {
return sendData(dev, data, QENC_CMD_ENCRYPT) rand.Seed(time.Now().UnixNano())
id := rand.Uint32()
return sendDataWrapper(dev, data, QENC_CMD_ENCRYPT, id)
} }
func QCmdDecrypt(dev *QEncDevice, data []byte) (err error) { func QCmdDecrypt(dev *QEncDevice, data []byte) (ret []byte, err error) {
return sendData(dev, data, QENC_CMD_DECRYPT) rand.Seed(time.Now().UnixNano())
id := rand.Uint32()
return sendDataWrapper(dev, data, QENC_CMD_DECRYPT, id)
} }
func QCmdGetMode(dev *QEncDevice) (retm QEncMode, retsm QEncSubMode, err error) { func QCmdGetMode(dev *QEncDevice) (retm QEncMode, retsm QEncSubMode, err error) {
buf, err := initBuffer(dev, QENC_CMD_GET_MODE) rand.Seed(time.Now().UnixNano())
id := rand.Uint32()
rbuf, err := sendDataWrapper(dev, []byte{}, QENC_CMD_GET_MODE, id)
if err != nil { if err != nil {
return retm, retsm, err return retm, retsm, err
} }
rbuf, err := dev.SendBuffer(buf) retm = QEncMode(rbuf[0])
if err != nil { retsm = QEncSubMode(rbuf[1])
return retm, retsm, err
}
dataLen := binary.LittleEndian.Uint16(rbuf)
if int(dataLen) != 2 {
return retm, retsm, fmt.Errorf("Invalid data")
}
retm = QEncMode(rbuf[3])
retsm = QEncSubMode(rbuf[4])
return retm, retsm, nil return retm, retsm, nil
} }
@ -184,119 +248,126 @@ func QCmdSetCfgTimeout(dev *QEncDevice, val uint8) (err error) {
return setCfg(dev, QENC_CFG_TIMEOUT, val) return setCfg(dev, QENC_CFG_TIMEOUT, val)
} }
func QCmdGetBuffer(dev *QEncDevice) (ret []byte, err error) {
return receiveData(dev, QENC_CMD_GET_BUFFER)
}
func QCmdGetKeys(dev *QEncDevice) (ret []byte, err error) { func QCmdGetKeys(dev *QEncDevice) (ret []byte, err error) {
return receiveData(dev, QENC_CMD_GET_KEYS) rand.Seed(time.Now().UnixNano())
id := rand.Uint32()
return sendDataWrapper(dev, []byte{}, QENC_CMD_GET_KEYS, id)
} }
func QCmdSetKeys(dev *QEncDevice, data []byte) (err error) { func QCmdSetKeys(dev *QEncDevice, data []byte) (err error) {
return sendData(dev, data, QENC_CMD_SET_KEYS) rand.Seed(time.Now().UnixNano())
id := rand.Uint32()
_, err = sendDataWrapper(dev, data, QENC_CMD_SET_KEYS, id)
return err
} }
func QCmdGetCfg(dev *QEncDevice) (ret *QCfg, err error) { func QCmdGetCfg(dev *QEncDevice) (ret *QCfg, err error) {
buf, err := initBuffer(dev, QENC_CMD_GET_CFG) rand.Seed(time.Now().UnixNano())
id := rand.Uint32()
rbuf, err := sendDataWrapper(dev, []byte{}, QENC_CMD_GET_CFG, id)
if err != nil { if err != nil {
return ret, err return ret, err
} }
rbuf, err := dev.SendBuffer(buf)
if err != nil {
return ret, err
}
dataLen := binary.LittleEndian.Uint16(rbuf)
if int(dataLen) != 6 {
return ret, fmt.Errorf("Invalid data")
}
ret = &QCfg{} ret = &QCfg{}
ret.val = make([]byte, 6) ret.val = make([]byte, 6)
copy(ret.val, rbuf[3:3+dataLen]) copy(ret.val, rbuf[0:6])
return ret, nil return ret, nil
} }
func setCfg(dev *QEncDevice, cfg QEncCfg, val uint8) (err error) { func setCfg(dev *QEncDevice, cfg QEncCfg, val uint8) (err error) {
buf, err := initBuffer(dev, QENC_CMD_SET_CFG) data := []byte{byte(cfg), val}
if err != nil {
return err
}
binary.LittleEndian.PutUint16(buf[3:], uint16(2)) rand.Seed(time.Now().UnixNano())
id := rand.Uint32()
buf[5] = byte(cfg) _, err = sendDataWrapper(dev, data, QENC_CMD_SET_CFG, id)
buf[6] = val return err
if _, err = dev.SendBuffer(buf); err != nil {
return err
}
return nil
} }
func sendData(dev *QEncDevice, data []byte, cmd QEncCmd) (err error) { func sendDataWrapper(dev *QEncDevice, data []byte, cmd QEncCmd, id uint32) (ret []byte, err error) {
buf, err := initBuffer(dev, cmd) done := make(chan bool)
if err != nil { msgc := make(chan string)
return err
}
dataLen := len(data) go func() {
binary.LittleEndian.PutUint16(buf[3:], uint16(dataLen)) defer func() { done <- true }()
ret, err = sendData(dev, data, cmd, id, msgc)
if dataLen <= (int(dev.GetBufSize()) - 5) { if err != nil {
copy(buf[5:], data) if QEncErrHandler != nil {
if _, err = dev.SendBuffer(buf); err != nil { QEncErrHandler(err)
return err }
return
} }
return nil }()
}
dataPos := 0 end := false
copy(buf[5:], data[:dev.GetBufSize()-5])
if _, err := dev.SendBuffer(buf); err != nil {
return err
}
dataPos += int(dev.GetBufSize()) - 5
buf[2] = byte(QENC_CMD_MORE_DATA)
for { for {
copy(buf[3:], data[dataPos:]) if end {
if _, err := dev.SendBuffer(buf); err != nil { if QEncEndHandler != nil {
return nil QEncEndHandler()
}
break
} }
if (dataLen - dataPos) <= (int(dev.GetBufSize()) - 3) { select {
return nil case <-done:
end = true
if err != nil {
return ret, err
}
case msg := <-msgc:
if QEncInfoHandler != nil {
QEncInfoHandler(msg)
}
default:
time.Sleep(500 * time.Millisecond)
} }
dataPos += int(dev.GetBufSize()) - 3
} }
return ret, err
} }
func receiveData(dev *QEncDevice, cmd QEncCmd) (ret []byte, err error) { func sendData(dev *QEncDevice, data []byte, cmd QEncCmd, id uint32, msg chan string) (ret []byte, err error) {
buf, err := initBuffer(dev, cmd) buf, err := initBuffer(dev, cmd)
if err != nil { if err != nil {
return ret, err return ret, err
} }
for { dataLen := len(data)
rbuf, err := dev.SendBuffer(buf) binary.LittleEndian.PutUint16(buf[3:], uint16(dataLen))
if err != nil { binary.LittleEndian.PutUint32(buf[5:], id)
return ret, err
}
if rbuf[0] == 1 { dataPos := 0
dataLen := binary.LittleEndian.Uint16(rbuf[1:3])
if int(dataLen) > int(dev.GetBufSize())-3 { for {
copy(buf[9:], data[dataPos:])
rbuf, err := dev.SendBuffer(buf, msg)
qerr := ToQEncError(err)
if err != nil && qerr.errCode != QENC_ERR_MORE_DATA {
return ret, err
} else if qerr.errCode == QENC_ERR_MORE_DATA {
resDataLen := binary.LittleEndian.Uint16(rbuf[1:3])
if int(resDataLen) > int(dev.GetBufSize())-3 {
return ret, fmt.Errorf("Invalid data") return ret, fmt.Errorf("Invalid data")
} }
b := make([]byte, dataLen) b := make([]byte, resDataLen)
copy(b, rbuf[3:]) copy(b, rbuf[3:])
ret = append(ret, b...) ret = append(ret, b...)
return ret, nil continue
} }
ret = append(ret, rbuf[1:]...) resDataLen := binary.LittleEndian.Uint16(rbuf[0:2])
if int(resDataLen) > int(dev.GetBufSize())-2 {
return ret, fmt.Errorf("Invalid data")
}
b := make([]byte, resDataLen)
copy(b, rbuf[2:])
ret = append(ret, b...)
if (dataLen - dataPos) <= (int(dev.GetBufSize()) - 9) {
return ret, err
}
dataPos += int(dev.GetBufSize()) - 9
} }
} }

View File

@ -45,7 +45,7 @@ func (d *QEncDevice) Close() (err error) {
return d.dev.Close() return d.dev.Close()
} }
func (d *QEncDevice) SendBuffer(data []byte) (ret []byte, err error) { func (d *QEncDevice) SendBuffer(data []byte, msg chan string) (ret []byte, err error) {
startTime := time.Now() startTime := time.Now()
for { for {
ret = make([]byte, d.bufSize) ret = make([]byte, d.bufSize)
@ -62,12 +62,22 @@ func (d *QEncDevice) SendBuffer(data []byte) (ret []byte, err error) {
return ret, fmt.Errorf("Failed to read: '%w'", err) return ret, fmt.Errorf("Failed to read: '%w'", err)
} }
var dataLen uint16
ret, err = QEncCheckResponse(ret) ret, err = QEncCheckResponse(ret)
if err != nil { if err != nil {
qerr := ToQEncError(err) qerr := ToQEncError(err)
if qerr.errCode != QENC_ERR_RETRY { if qerr.errCode != QENC_ERR_RETRY {
return ret, err return ret, err
} }
fmt.Println("RETRY")
dataLen = binary.LittleEndian.Uint16(ret[:2])
if int(dataLen) == 5 {
if msg != nil {
timeout := binary.LittleEndian.Uint32(ret[4:8])
cmd := QEncCmd(ret[3])
msg <- fmt.Sprintf("Allow request for '%s' (timeout: %ds)", cmd, timeout)
}
}
time.Sleep(time.Second * time.Duration(d.retryWait)) time.Sleep(time.Second * time.Duration(d.retryWait))
} else { } else {
return ret, err return ret, err
@ -114,7 +124,7 @@ func (d *QEncDevice) setBufSize() (err error) {
return fmt.Errorf("Invalid data") return fmt.Errorf("Invalid data")
} }
d.bufSize = buf[3] d.bufSize = buf[2]
return nil return nil
} }
return fmt.Errorf("Unsupported device: '%w'", err) return fmt.Errorf("Unsupported device: '%w'", err)

View File

@ -10,6 +10,7 @@ const (
QENC_ERR_INVALID QEncErr = 0x04 QENC_ERR_INVALID QEncErr = 0x04
QENC_ERR_RETRY QEncErr = 0x05 QENC_ERR_RETRY QEncErr = 0x05
QENC_ERR_HW_SUPPORT QEncErr = 0x06 QENC_ERR_HW_SUPPORT QEncErr = 0x06
QENC_ERR_MORE_DATA QEncErr = 0x07
// device retry timeout // device retry timeout
QENC_ERR_TIMEOUT QEncErr = 0xFF QENC_ERR_TIMEOUT QEncErr = 0xFF
) )
@ -32,6 +33,8 @@ func (e *QEncError) Error() string {
return "Retry request" return "Retry request"
case QENC_ERR_HW_SUPPORT: case QENC_ERR_HW_SUPPORT:
return "Not supported by hardware" return "Not supported by hardware"
case QENC_ERR_MORE_DATA:
return "More data available"
case QENC_ERR_TIMEOUT: case QENC_ERR_TIMEOUT:
return "Timeout reached" return "Timeout reached"
default: default:
@ -47,6 +50,12 @@ func QEncCheckResponse(data []byte) (ret []byte, err error) {
rerr := new(QEncError) rerr := new(QEncError)
rerr.errCode = QEncErr(data[0]) rerr.errCode = QEncErr(data[0])
if data[0] == byte(QENC_ERR_RETRY) {
ret = data[1:]
} else {
ret = data
}
return ret, rerr return ret, rerr
} }