Skip to content

Commit

Permalink
Merge pull request #3 from solipsis/flash-validate
Browse files Browse the repository at this point in the history
Flash Hashing and Flash Dumping
  • Loading branch information
solipsis authored Mar 2, 2018
2 parents 6acbee9 + f03a290 commit 87dde94
Show file tree
Hide file tree
Showing 8 changed files with 765 additions and 350 deletions.
62 changes: 62 additions & 0 deletions cmd/flashDump.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package cmd

import (
"bytes"
"encoding/binary"
"encoding/hex"
"fmt"
"io/ioutil"
"os"

"github.com/spf13/cobra"
)

func init() {
flashDumpCmd.Flags().StringVarP(&memAddress, "address", "a", "", "memory address")
flashDumpCmd.Flags().StringVarP(&file, "file", "f", "", "store result to file")
flashDumpCmd.Flags().Uint32VarP(&length, "length", "l", 0, "length of memory to dump")
rootCmd.AddCommand(flashDumpCmd)
}

var file string

var flashDumpCmd = &cobra.Command{
Use: "flashDump",
Short: "dump certain section of flash",
Long: "dumps certain section of flash",
Run: func(cmd *cobra.Command, args []string) {

addrStr := mustParseHex(memAddress)
addr := binary.BigEndian.Uint32(addrStr)
buf := bytes.Buffer{}

for length > 0 {
l := min(1024, length)
data, err := kk.FlashDump(addr, l)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
buf.Write(data)

length -= l
addr += l
}

if file != "" {
if err := ioutil.WriteFile(file, buf.Bytes(), 0644); err != nil {
fmt.Println(err)
os.Exit(1)
}
} else {
fmt.Println(hex.EncodeToString(buf.Bytes()))
}
},
}

func min(x, y uint32) uint32 {
if x < y {
return x
}
return y
}
40 changes: 40 additions & 0 deletions cmd/flashHash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package cmd

import (
"encoding/hex"
"fmt"
"os"

"github.com/spf13/cobra"
)

func init() {
flashHashCmd.Flags().Uint32VarP(&length, "length", "l", 0, "length of memory to hash")
flashHashCmd.Flags().StringVarP(&challenge, "challenge", "c", "", "challenge response nonce")
flashHashCmd.Flags().StringVarP(&memAddress, "address", "a", "", "memory address")
rootCmd.AddCommand(flashHashCmd)
}

var (
length uint32
memAddress string
challenge string
)

var flashHashCmd = &cobra.Command{
Use: "flashHash",
Short: "Request hash of certain segment of flash memory",
Long: "Requests hash of certain segment of flash memory",
Run: func(cmd *cobra.Command, args []string) {

nonce := mustParseHex(challenge)
addr := mustParseHex(memAddress)
data, err := kk.FlashHash(addr, nonce, length)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

fmt.Println(hex.EncodeToString(data))
},
}
41 changes: 41 additions & 0 deletions cmd/writeFlash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cmd

import (
"encoding/binary"
"encoding/hex"
"fmt"
"os"

"github.com/spf13/cobra"
)

func init() {
writeHashCmd.Flags().StringVarP(&memAddress, "address", "a", "", "memory address to begin writing")
writeHashCmd.Flags().StringVarP(&writeData, "sector", "s", "", "data to write in hex")
rootCmd.AddCommand(writeHashCmd)
}

// Data to write to device
var writeData string

var writeHashCmd = &cobra.Command{
Use: "writeFlash",
Short: "Write data over flash sectors",
Long: "Writes data over flash sectors",
Run: func(cmd *cobra.Command, args []string) {

// data to write
data := mustParseHex(writeData)

// Convert hex address to uint32
addr := binary.BigEndian.Uint32(mustParseHex(memAddress))

resp, err := kk.FlashWrite(addr, data)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

fmt.Println(hex.EncodeToString(resp))
},
}
50 changes: 50 additions & 0 deletions pkg/keepkey/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,56 @@ func (kk *Keepkey) UploadFirmware(path string) (int, error) {
return len(data), nil
}

// WriteFlash writes the given block of data to the given address
// data should be at most 1024 bytes at a time
func (kk *Keepkey) FlashWrite(address uint32, data []byte) ([]byte, error) {

write := &kkProto.FlashWrite{
Address: &address,
Data: data,
}

resp := new(kkProto.FlashHashResponse)
if _, err := kk.keepkeyExchange(write, resp); err != nil {
return []byte{}, err
}

return resp.GetData(), nil
}

// DumpFlash dumps length bytes of data from a given address
// length should be at most 1024
func (kk *Keepkey) FlashDump(address, length uint32) ([]byte, error) {

dump := &kkProto.DebugLinkFlashDump{
Address: &address,
Length: &length,
}

resp := new(kkProto.DebugLinkFlashDumpResponse)
if _, err := kk.keepkeyExchange(dump, resp); err != nil {
return []byte{}, err
}

return resp.GetData(), nil
}

func (kk *Keepkey) FlashHash(address, challenge []byte, length uint32) ([]byte, error) {

addr := binary.BigEndian.Uint32(address)
flash := &kkProto.FlashHash{
Address: &addr,
Length: &length,
Challenge: challenge,
}

hash := new(kkProto.FlashHashResponse)
if _, err := kk.keepkeyExchange(flash, hash); err != nil {
return []byte{}, err
}
return hash.GetData(), nil
}

// EthereumGetAddress returns the ethereum address associated with the given node path
// Optionally you can display the address on the screen
func (kk *Keepkey) EthereumGetAddress(path []uint32, display bool) ([]byte, error) {
Expand Down
16 changes: 7 additions & 9 deletions pkg/keepkey/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func GetDevices() ([]*Keepkey, error) {

kk := newKeepkey()

// tie a keepkey to its debug interface
// tuple of keepkey and optionally its debug interface
type infoPair struct {
device, debug hid.DeviceInfo
}
Expand All @@ -43,12 +43,12 @@ func GetDevices() ([]*Keepkey, error) {
// corresponding debug link if enabled
deviceMap := make(map[string]*infoPair)
for _, info := range hid.Enumerate(kk.vendorID, 0) {

// TODO: revisit this when keepkey adds additional product id's
if info.ProductID == kk.productID {

// get all but the last character of the hid path
// if the path ends with 0 it is a device if it ends with 1
// the device is advertising a debug connection
pathKey := info.Path[:len(info.Path)-1]
// Use serial string to differentiate between different keepkeys
pathKey := info.Serial
if deviceMap[pathKey] == nil {
deviceMap[pathKey] = new(infoPair)
}
Expand All @@ -57,7 +57,6 @@ func GetDevices() ([]*Keepkey, error) {
if strings.HasSuffix(info.Path, "1") {
deviceMap[pathKey].debug = info
} else {
fmt.Println("Device: ", info)
deviceMap[pathKey].device = info
}
}
Expand Down Expand Up @@ -153,9 +152,8 @@ func (kk *Keepkey) keepkeyExchange(req proto.Message, results ...proto.Message)
}
}

// TODO; support debug requests that return data
// don't wait for response if sending debug buttonPress
if debug {
if debug && kkProto.Name(kkProto.Type(req)) == "MessageType_DebugLinkDecision" {
return 0, nil
}

Expand Down Expand Up @@ -250,7 +248,7 @@ func (kk *Keepkey) keepkeyExchange(req proto.Message, results ...proto.Message)
// Is the message one we need to send over the debug HID interface
func isDebugMessage(req interface{}) bool {
switch req.(type) {
case *kkProto.DebugLinkDecision, *kkProto.DebugLinkFillConfig, *kkProto.DebugLinkGetState:
case *kkProto.DebugLinkDecision, *kkProto.DebugLinkFillConfig, *kkProto.DebugLinkGetState, *kkProto.DebugLinkFlashDump:
return true
}
return false
Expand Down
Loading

0 comments on commit 87dde94

Please sign in to comment.