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 }