398 lines
8.4 KiB
Go
398 lines
8.4 KiB
Go
package qmkenc
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math/rand"
|
|
"time"
|
|
)
|
|
|
|
var magicHeader = []byte{0x03, 0xFF}
|
|
|
|
type QEncCmd byte
|
|
type QEncInfoFct func(string)
|
|
type QEncEndFct func()
|
|
type QEncErrFct func(error)
|
|
|
|
var QEncInfoHandler QEncInfoFct
|
|
var QEncEndHandler QEncEndFct
|
|
var QEncErrHandler QEncErrFct
|
|
|
|
const (
|
|
QENC_CMD_RESET QEncCmd = 0x00
|
|
QENC_CMD_ENCRYPT QEncCmd = 0x01
|
|
QENC_CMD_DECRYPT QEncCmd = 0x02
|
|
QENC_CMD_MORE_DATA QEncCmd = 0x03
|
|
QENC_CMD_UNLOCK QEncCmd = 0x04
|
|
QENC_CMD_LOCK QEncCmd = 0x05
|
|
QENC_CMD_SET_CFG QEncCmd = 0x06
|
|
QENC_CMD_GET_MODE QEncCmd = 0x07
|
|
QENC_CMD_GET_BUFFER QEncCmd = 0x08
|
|
QENC_CMD_GET_KEYS QEncCmd = 0x09
|
|
QENC_CMD_GET_BUFFSIZE QEncCmd = 0x0A
|
|
QENC_CMD_SET_KEYS QEncCmd = 0x0B
|
|
QENC_CMD_GET_CFG QEncCmd = 0x0C
|
|
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
|
|
|
|
const (
|
|
QENC_MODE_CLOSED QEncMode = 0x00
|
|
QENC_MODE_OPEN QEncMode = 0x01
|
|
QENC_MODE_LOAD QEncMode = 0x02
|
|
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
|
|
|
|
const (
|
|
QENC_SUB_MODE_NONE QEncSubMode = 0x00
|
|
QENC_SUB_MODE_SEED QEncSubMode = 0x01
|
|
QENC_SUB_MODE_PASSWORD QEncSubMode = 0x02
|
|
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
|
|
|
|
const (
|
|
QENC_CFG_PARANOIA QEncCfg = 0x00
|
|
QENC_CFG_SECURE QEncCfg = 0x01
|
|
QENC_CFG_MAX_ERROR QEncCfg = 0x02
|
|
QENC_CFG_TIMEOUT QEncCfg = 0x03
|
|
)
|
|
|
|
type QCfg struct {
|
|
val []byte
|
|
}
|
|
|
|
func (q *QCfg) MaxError() int {
|
|
return int(q.val[0])
|
|
}
|
|
|
|
func (q *QCfg) ErrorCount() int {
|
|
return int(q.val[1])
|
|
}
|
|
|
|
func (q *QCfg) ParanoiaMode() bool {
|
|
if q.val[2] == 0 {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (q *QCfg) SecureMode() bool {
|
|
if q.val[3] == 0 {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (q *QCfg) Timeout() int {
|
|
return int(q.val[4])
|
|
}
|
|
|
|
func (q *QCfg) Initialized() bool {
|
|
if q.val[5] == 0 {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func QCmdReset(dev *QEncDevice) (err error) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
id := rand.Uint32()
|
|
_, err = sendDataWrapper(dev, []byte{}, QENC_CMD_RESET, id)
|
|
return err
|
|
}
|
|
|
|
func QCmdUnlock(dev *QEncDevice) (err error) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
id := rand.Uint32()
|
|
_, err = sendDataWrapper(dev, []byte{}, QENC_CMD_UNLOCK, id)
|
|
return err
|
|
}
|
|
|
|
func QCmdLock(dev *QEncDevice) (err error) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
id := rand.Uint32()
|
|
_, err = sendDataWrapper(dev, []byte{}, QENC_CMD_LOCK, id)
|
|
return err
|
|
}
|
|
|
|
func QCmdInitialize(dev *QEncDevice) (err error) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
id := rand.Uint32()
|
|
_, err = sendDataWrapper(dev, []byte{}, QENC_CMD_INITIALIZE, id)
|
|
return err
|
|
}
|
|
|
|
func QCmdEncrypt(dev *QEncDevice, data []byte) (ret []byte, err error) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
id := rand.Uint32()
|
|
return sendDataWrapper(dev, data, QENC_CMD_ENCRYPT, id)
|
|
}
|
|
|
|
func QCmdDecrypt(dev *QEncDevice, data []byte) (ret []byte, err error) {
|
|
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) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
id := rand.Uint32()
|
|
rbuf, err := sendDataWrapper(dev, []byte{}, QENC_CMD_GET_MODE, id)
|
|
if err != nil {
|
|
return retm, retsm, err
|
|
}
|
|
|
|
retm = QEncMode(rbuf[0])
|
|
retsm = QEncSubMode(rbuf[1])
|
|
return retm, retsm, nil
|
|
}
|
|
|
|
func QCmdSetCfgParanoia(dev *QEncDevice) (err error) {
|
|
return setCfg(dev, QENC_CFG_PARANOIA, 1)
|
|
}
|
|
|
|
func QCmdSetCfgSecure(dev *QEncDevice, val bool) (err error) {
|
|
if val {
|
|
return setCfg(dev, QENC_CFG_SECURE, 1)
|
|
}
|
|
return setCfg(dev, QENC_CFG_SECURE, 0)
|
|
}
|
|
|
|
func QCmdSetCfgMaxError(dev *QEncDevice, val uint8) (err error) {
|
|
if val < 0 || val > 15 {
|
|
return fmt.Errorf("Invalid value")
|
|
}
|
|
return setCfg(dev, QENC_CFG_MAX_ERROR, val)
|
|
}
|
|
|
|
func QCmdSetCfgTimeout(dev *QEncDevice, val uint8) (err error) {
|
|
if val < 0 || val > 50 {
|
|
return fmt.Errorf("Invalid value")
|
|
}
|
|
return setCfg(dev, QENC_CFG_TIMEOUT, val)
|
|
}
|
|
|
|
func QCmdGetKeys(dev *QEncDevice) (ret []byte, err error) {
|
|
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) {
|
|
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) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
id := rand.Uint32()
|
|
rbuf, err := sendDataWrapper(dev, []byte{}, QENC_CMD_GET_CFG, id)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
|
|
ret = &QCfg{}
|
|
ret.val = make([]byte, 6)
|
|
copy(ret.val, rbuf[0:6])
|
|
return ret, nil
|
|
}
|
|
|
|
func setCfg(dev *QEncDevice, cfg QEncCfg, val uint8) (err error) {
|
|
data := []byte{byte(cfg), val}
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
id := rand.Uint32()
|
|
_, err = sendDataWrapper(dev, data, QENC_CMD_SET_CFG, id)
|
|
return err
|
|
}
|
|
|
|
func sendDataWrapper(dev *QEncDevice, data []byte, cmd QEncCmd, id uint32) (ret []byte, err error) {
|
|
if err = dev.Open(); err != nil {
|
|
if QEncInfoHandler != nil {
|
|
QEncErrHandler(err)
|
|
}
|
|
return nil, err
|
|
}
|
|
if err = dev.Lock(); err != nil {
|
|
if QEncInfoHandler != nil {
|
|
QEncErrHandler(err)
|
|
}
|
|
return nil, err
|
|
}
|
|
defer dev.Close()
|
|
|
|
done := make(chan bool)
|
|
msgc := make(chan string)
|
|
|
|
go func() {
|
|
defer func() { done <- true }()
|
|
ret, err = sendData(dev, data, cmd, id, msgc)
|
|
if err != nil {
|
|
if QEncErrHandler != nil {
|
|
QEncErrHandler(err)
|
|
}
|
|
return
|
|
}
|
|
}()
|
|
|
|
end := false
|
|
for {
|
|
if end {
|
|
if QEncEndHandler != nil {
|
|
QEncEndHandler()
|
|
}
|
|
break
|
|
}
|
|
select {
|
|
case <-done:
|
|
end = true
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
case msg := <-msgc:
|
|
if QEncInfoHandler != nil {
|
|
QEncInfoHandler(msg)
|
|
}
|
|
default:
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
return ret, err
|
|
}
|
|
|
|
func sendData(dev *QEncDevice, data []byte, cmd QEncCmd, id uint32, msg chan string) (ret []byte, err error) {
|
|
buf, err := initBuffer(dev, cmd)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
|
|
dataLen := len(data)
|
|
binary.LittleEndian.PutUint16(buf[3:], uint16(dataLen))
|
|
binary.LittleEndian.PutUint32(buf[5:], id)
|
|
|
|
dataPos := 0
|
|
|
|
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")
|
|
}
|
|
|
|
b := make([]byte, resDataLen)
|
|
copy(b, rbuf[3:])
|
|
ret = append(ret, b...)
|
|
continue
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
func initBuffer(dev *QEncDevice, cmd QEncCmd) (ret []byte, err error) {
|
|
ret = make([]byte, dev.GetBufSize())
|
|
|
|
if copy(ret, magicHeader) != 2 {
|
|
return ret, fmt.Errorf("Invalid magic Header")
|
|
}
|
|
ret[2] = byte(cmd)
|
|
|
|
return ret, nil
|
|
}
|