Skip to content

Commit

Permalink
增加KeyStore文件查看工具
Browse files Browse the repository at this point in the history
  • Loading branch information
chai2010 committed Dec 19, 2019
1 parent 3900578 commit de9152e
Show file tree
Hide file tree
Showing 5 changed files with 376 additions and 0 deletions.
48 changes: 48 additions & 0 deletions cmd/ethutil-cat-keystore/get_passwd.go
@@ -0,0 +1,48 @@
// Copyright 2014 chaishushan@gmail.com. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
"os"
)

// GetPasswd returns the password read from the terminal without echoing input.
// The returned byte array does not include end-of-line characters.
func GetPasswd() []byte {
return getPasswd(false)
}

// GetPasswdMasked returns the password read from the terminal, echoing asterisks.
// The returned byte array does not include end-of-line characters.
func GetPasswdMasked() []byte {
return getPasswd(true)
}

// getPasswd returns the input read from terminal.
// If masked is true, typing will be matched by asterisks on the screen.
// Otherwise, typing will echo nothing.
func getPasswd(masked bool) []byte {
var pass, bs, mask []byte
if masked {
bs = []byte("\b \b")
mask = []byte("*")
}

for {
if v := getch(); v == 127 || v == 8 {
if l := len(pass); l > 0 {
pass = pass[:l-1]
os.Stdout.Write(bs)
}
} else if v == 13 || v == 10 {
break
} else {
pass = append(pass, v)
os.Stdout.Write(mask)
}
}
println()
return pass
}
76 changes: 76 additions & 0 deletions cmd/ethutil-cat-keystore/get_passwd_darwin.go
@@ -0,0 +1,76 @@
// Copyright 2014 chaishushan@gmail.com. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !windows

package main

import (
"runtime"
"syscall"
"unsafe"
)

// These constants are declared here, rather than importing
// them from the syscall package as some syscall packages, even
// on linux, for example gccgo, do not declare them.
var ioctlReadTermios = func() uintptr {
if runtime.GOOS == "linux" {
return 0x5401 // syscall.TCGETS
} else {
return syscall.TIOCGETA
}
}
var ioctlWriteTermios = func() uintptr {
if runtime.GOOS == "linux" {
return 0x5402 // syscall.TCSETS
} else {
return syscall.TIOCSETA
}
}

// terminalState contains the state of a terminal.
type terminalState struct {
termios syscall.Termios
}

// terminalMakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func terminalMakeRaw(fd int) (*terminalState, error) {
var oldState terminalState
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios(), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
return nil, err
}

newState := oldState.termios
newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios(), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
return nil, err
}

return &oldState, nil
}

// terminalRestore restores the terminal connected to the given file descriptor to a
// previous state.
func terminalRestore(fd int, state *terminalState) error {
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios(), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
return err
}

func getch() byte {
if oldState, err := terminalMakeRaw(0); err != nil {
panic(err)
} else {
defer terminalRestore(0, oldState)
}

var buf [1]byte
if n, err := syscall.Read(0, buf[:]); n == 0 || err != nil {
panic(err)
}
return buf[0]
}
67 changes: 67 additions & 0 deletions cmd/ethutil-cat-keystore/get_passwd_linux.go
@@ -0,0 +1,67 @@
// Copyright 2014 chaishushan@gmail.com. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !windows

package main

import (
"syscall"
"unsafe"
)

// These constants are declared here, rather than importing
// them from the syscall package as some syscall packages, even
// on linux, for example gccgo, do not declare them.
var ioctlReadTermios = func() uintptr {
return 0x5401 // syscall.TCGETS
}
var ioctlWriteTermios = func() uintptr {
return 0x5402 // syscall.TCSETS
}

// terminalState contains the state of a terminal.
type terminalState struct {
termios syscall.Termios
}

// terminalMakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func terminalMakeRaw(fd int) (*terminalState, error) {
var oldState terminalState
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios(), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
return nil, err
}

newState := oldState.termios
newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios(), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
return nil, err
}

return &oldState, nil
}

// terminalRestore restores the terminal connected to the given file descriptor to a
// previous state.
func terminalRestore(fd int, state *terminalState) error {
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios(), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
return err
}

func getch() byte {
if oldState, err := terminalMakeRaw(0); err != nil {
panic(err)
} else {
defer terminalRestore(0, oldState)
}

var buf [1]byte
if n, err := syscall.Read(0, buf[:]); n == 0 || err != nil {
panic(err)
}
return buf[0]
}
56 changes: 56 additions & 0 deletions cmd/ethutil-cat-keystore/get_passwd_windows.go
@@ -0,0 +1,56 @@
// Copyright 2014 chaishushan@gmail.com. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
"syscall"
"unicode/utf16"
"unsafe"
)

var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procReadConsole = modkernel32.NewProc("ReadConsoleW")
procGetConsoleMode = modkernel32.NewProc("GetConsoleMode")
procSetConsoleMode = modkernel32.NewProc("SetConsoleMode")
)

func getch() byte {
var mode uint32
pMode := &mode
procGetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(unsafe.Pointer(pMode)))

var echoMode, lineMode uint32
echoMode = 4
lineMode = 2
var newMode uint32
newMode = mode ^ (echoMode | lineMode)

procSetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(newMode))

line := make([]uint16, 1)
pLine := &line[0]
var n uint16
procReadConsole.Call(
uintptr(syscall.Stdin), uintptr(unsafe.Pointer(pLine)), uintptr(len(line)),
uintptr(unsafe.Pointer(&n)),
)

// For some reason n returned seems to big by 2 (Null terminated maybe?)
if n > 2 {
n -= 2
}

b := []byte(string(utf16.Decode(line[:n])))

procSetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(mode))

// Not sure how this could happen, but it did for someone
if len(b) > 0 {
return b[0]
} else {
return 13
}
}
129 changes: 129 additions & 0 deletions cmd/ethutil-cat-keystore/main.go
@@ -0,0 +1,129 @@
// 以太坊工具箱(零第三方库依赖) 版权 @2019 柴树杉。

// 以太坊KeyStore文件查看器
//
// 创建KeyStore文件步骤:
// 1. 准备好私钥, 保存到key.txt文件
// 2. 执行 geth account import --keystore `pwd` key.txt
// 3. 通过步骤2中输入的密码可以查看生成的文件
// 4. 私钥可以使用 <ethutil-vanity-gen> 工具生成
package main

import (
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"

"github.com/chai2010/ethutil"
)

var (
flagPassword = flag.String("password", "", "设置KeyStore文件的密码(默认手工输入)")
flagGlobMatch = flag.Bool("glob-match", false, "采用Glob模式匹配文件名")
flagShowKey = flag.Bool("show-key", false, "显示私钥")
flagHelp = flag.Bool("h", false, "显示帮助")
)

func init() {
flag.Usage = func() {
fmt.Println("以太坊KeyStore文件查看器")
fmt.Println()

fmt.Println(" # 指定文件名")
fmt.Println(" ethutil-cat-keystore file.json")
fmt.Println(" ethutil-cat-keystore file.json file2.json")
fmt.Println()

fmt.Println(" # 显示私钥")
fmt.Println(" ethutil-cat-keystore -show-key file.json")
fmt.Println(" ethutil-cat-keystore -show-key file.json file2.json")
fmt.Println()

fmt.Println(" # Glob模式匹配")
fmt.Println(" ethutil-cat-keystore -glob-match file?.json")
fmt.Println(" ethutil-cat-keystore -glob-match file*.json")
fmt.Println()

fmt.Println("参数说明:")
flag.PrintDefaults()
fmt.Println()

fmt.Println("https://github.com/chai2010/ethutil")
fmt.Println("版权 @2019 柴树杉")
}
}

func main() {
flag.Parse()

// 显示帮助信息
if *flagHelp || len(os.Args) < 2 {
flag.Usage()
os.Exit(0)
}

// 指定输入文件名
if flag.NArg() == 0 {
fmt.Fprintf(os.Stderr, "错误: 缺少文件名!\n")
os.Exit(-1)
}

// 读取文件名列表
var files = flag.Args()

// Glob模式展开文件列表
if *flagGlobMatch {
files = []string{}
for _, pattern := range flag.Args() {
matches, err := filepath.Glob(pattern)
if err != nil {
fmt.Fprintf(os.Stderr, "错误: %v\n", err)
os.Exit(-1)
}
files = append(files, matches...)
}
}

// 手工输入密码
if *flagPassword == "" {
fmt.Printf("输入密码: ")
*flagPassword = string(GetPasswdMasked())
if len(*flagPassword) <= 0 {
fmt.Fprintf(os.Stderr, "错误: 密码不能为空!\n")
os.Exit(-1)
}
}

// 处理全部的ks文件
for _, s := range files {
// 读取ks文件
keyjson, err := ioutil.ReadFile(s)
if err != nil {
fmt.Fprintf(os.Stderr, "错误: 读文件 %q 失败: %v\n", s, err)
os.Exit(-1)
}

// 解码ks文件
uuid, privateKey, err := ethutil.KeyStoreDecryptKey(
[]byte(keyjson), *flagPassword,
)
if err != nil {
fmt.Fprintf(os.Stderr, "错误: 解密 %q 失败: %v\n", s, err)
os.Exit(-1)
}

if *flagShowKey {
fmt.Printf("<uuid:%s> <address:%s> <key:%s> <file:%s>\n", uuid,
ethutil.GenAddressFromPrivateKey(privateKey), privateKey,
filepath.Clean(s),
)
} else {
fmt.Printf("<uuid:%s> <address:%s> <file:%s>\n", uuid,
ethutil.GenAddressFromPrivateKey(privateKey),
filepath.Clean(s),
)
}
}
}

0 comments on commit de9152e

Please sign in to comment.