Browse Source

Merge pull request #30 from tendermint/develop

Develop
pull/1782/head
Ethan Buchman 7 years ago
committed by GitHub
parent
commit
311e8c1bf0
38 changed files with 330 additions and 2304 deletions
  1. +17
    -0
      CHANGELOG.md
  2. +3
    -21
      Makefile
  3. +4
    -835
      README.md
  4. +0
    -117
      cmd/README.md
  5. +0
    -49
      cmd/delete.go
  6. +0
    -42
      cmd/get.go
  7. +0
    -30
      cmd/keys/main.go
  8. +0
    -34
      cmd/list.go
  9. +0
    -94
      cmd/new.go
  10. +0
    -61
      cmd/recover.go
  11. +0
    -50
      cmd/root.go
  12. +0
    -110
      cmd/serve.go
  13. +0
    -53
      cmd/update.go
  14. +0
    -144
      cmd/utils.go
  15. +20
    -59
      glide.lock
  16. +1
    -0
      glide.yaml
  17. +14
    -3
      hd/address.go
  18. +53
    -0
      hd/hd_test.go
  19. +12
    -6
      keys/cryptostore/encoder.go
  20. +45
    -3
      keys/cryptostore/encoder_test.go
  21. +19
    -8
      keys/cryptostore/generator.go
  22. +19
    -4
      keys/cryptostore/holder.go
  23. +29
    -10
      keys/cryptostore/holder_test.go
  24. +5
    -1
      keys/cryptostore/storage_test.go
  25. +73
    -6
      keys/ecc.go
  26. +13
    -16
      keys/ecc_test.go
  27. +0
    -10
      keys/tx/docs.go
  28. +0
    -67
      keys/tx/multi.go
  29. +0
    -78
      keys/tx/multi_test.go
  30. +0
    -57
      keys/tx/one.go
  31. +0
    -74
      keys/tx/one_test.go
  32. +0
    -76
      keys/tx/reader.go
  33. +0
    -72
      keys/tx/reader_test.go
  34. +1
    -0
      keys/wordcodec.go
  35. +1
    -1
      keys/wordcodec_test.go
  36. +0
    -1
      signature.go
  37. +0
    -111
      tests/keys.sh
  38. +1
    -1
      version.go

+ 17
- 0
CHANGELOG.md View File

@ -1,5 +1,22 @@
# Changelog
## 0.3.0 (September 22, 2017)
BREAKING CHANGES:
- Remove `cmd` and `keys/tx` packages altogether: move it to the cosmos-sdk
- `cryptostore.Generator` takes a secret
- Remove `String()` from `Signature` interface
FEATURES:
- `keys`: add CRC16 error correcting code
IMPROVEMENTS:
- Allow no passwords on keys for development convenience
## 0.2.1 (June 21, 2017)
- Improve keys command


+ 3
- 21
Makefile View File

@ -1,32 +1,14 @@
.PHONEY: all docs test install get_vendor_deps ensure_tools codegen wordlist
.PHONEY: all test install get_vendor_deps ensure_tools codegen wordlist
GOTOOLS = \
github.com/Masterminds/glide \
github.com/jteeuwen/go-bindata/go-bindata
REPO:=github.com/tendermint/go-crypto
docs:
@go get github.com/davecheney/godoc2md
godoc2md $(REPO) > README.md
all: get_vendor_deps test
all: get_vendor_deps install test
install:
go install ./cmd/keys
test: test_unit test_cli
test_unit:
test:
go test `glide novendor`
#go run tests/tendermint/*.go
test_cli: tests/shunit2
# sudo apt-get install jq
@./tests/keys.sh
tests/shunit2:
wget "https://raw.githubusercontent.com/kward/shunit2/master/source/2.1/src/shunit2" \
-q -O tests/shunit2
get_vendor_deps: ensure_tools
@rm -rf vendor/


+ 4
- 835
README.md View File

@ -1,837 +1,6 @@
# go-crypto [![GoDoc](https://godoc.org/github.com/tendermint/go-crypto?status.svg)](https://godoc.org/github.com/tendermint/go-crypto)
go-crypto is the cryptographic package adapted for Tendermint's uses
# crypto
`import "github.com/tendermint/go-crypto"`
* [Overview](#pkg-overview)
* [Index](#pkg-index)
* [Subdirectories](#pkg-subdirectories)
## <a name="pkg-overview">Overview</a>
## <a name="pkg-index">Index</a>
* [Constants](#pkg-constants)
* [func CRandBytes(numBytes int) []byte](#CRandBytes)
* [func CRandHex(numDigits int) string](#CRandHex)
* [func CReader() io.Reader](#CReader)
* [func DecodeArmor(armorStr string) (blockType string, headers map[string]string, data []byte, err error)](#DecodeArmor)
* [func DecryptSymmetric(ciphertext []byte, secret []byte) (plaintext []byte, err error)](#DecryptSymmetric)
* [func EncodeArmor(blockType string, headers map[string]string, data []byte) string](#EncodeArmor)
* [func EncryptSymmetric(plaintext []byte, secret []byte) (ciphertext []byte)](#EncryptSymmetric)
* [func MixEntropy(seedBytes []byte)](#MixEntropy)
* [func Ripemd160(bytes []byte) []byte](#Ripemd160)
* [func Sha256(bytes []byte) []byte](#Sha256)
* [type PrivKey](#PrivKey)
* [func PrivKeyFromBytes(privKeyBytes []byte) (privKey PrivKey, err error)](#PrivKeyFromBytes)
* [type PrivKeyEd25519](#PrivKeyEd25519)
* [func GenPrivKeyEd25519() PrivKeyEd25519](#GenPrivKeyEd25519)
* [func GenPrivKeyEd25519FromSecret(secret []byte) PrivKeyEd25519](#GenPrivKeyEd25519FromSecret)
* [func (privKey PrivKeyEd25519) Bytes() []byte](#PrivKeyEd25519.Bytes)
* [func (privKey PrivKeyEd25519) Equals(other PrivKey) bool](#PrivKeyEd25519.Equals)
* [func (privKey PrivKeyEd25519) Generate(index int) PrivKeyEd25519](#PrivKeyEd25519.Generate)
* [func (p PrivKeyEd25519) MarshalJSON() ([]byte, error)](#PrivKeyEd25519.MarshalJSON)
* [func (privKey PrivKeyEd25519) PubKey() PubKey](#PrivKeyEd25519.PubKey)
* [func (privKey PrivKeyEd25519) Sign(msg []byte) Signature](#PrivKeyEd25519.Sign)
* [func (privKey PrivKeyEd25519) String() string](#PrivKeyEd25519.String)
* [func (privKey PrivKeyEd25519) ToCurve25519() *[32]byte](#PrivKeyEd25519.ToCurve25519)
* [func (p *PrivKeyEd25519) UnmarshalJSON(enc []byte) error](#PrivKeyEd25519.UnmarshalJSON)
* [type PrivKeyS](#PrivKeyS)
* [func (p PrivKeyS) Empty() bool](#PrivKeyS.Empty)
* [func (p PrivKeyS) MarshalJSON() ([]byte, error)](#PrivKeyS.MarshalJSON)
* [func (p *PrivKeyS) UnmarshalJSON(data []byte) (err error)](#PrivKeyS.UnmarshalJSON)
* [type PrivKeySecp256k1](#PrivKeySecp256k1)
* [func GenPrivKeySecp256k1() PrivKeySecp256k1](#GenPrivKeySecp256k1)
* [func GenPrivKeySecp256k1FromSecret(secret []byte) PrivKeySecp256k1](#GenPrivKeySecp256k1FromSecret)
* [func (privKey PrivKeySecp256k1) Bytes() []byte](#PrivKeySecp256k1.Bytes)
* [func (privKey PrivKeySecp256k1) Equals(other PrivKey) bool](#PrivKeySecp256k1.Equals)
* [func (p PrivKeySecp256k1) MarshalJSON() ([]byte, error)](#PrivKeySecp256k1.MarshalJSON)
* [func (privKey PrivKeySecp256k1) PubKey() PubKey](#PrivKeySecp256k1.PubKey)
* [func (privKey PrivKeySecp256k1) Sign(msg []byte) Signature](#PrivKeySecp256k1.Sign)
* [func (privKey PrivKeySecp256k1) String() string](#PrivKeySecp256k1.String)
* [func (p *PrivKeySecp256k1) UnmarshalJSON(enc []byte) error](#PrivKeySecp256k1.UnmarshalJSON)
* [type PubKey](#PubKey)
* [func PubKeyFromBytes(pubKeyBytes []byte) (pubKey PubKey, err error)](#PubKeyFromBytes)
* [type PubKeyEd25519](#PubKeyEd25519)
* [func (pubKey PubKeyEd25519) Address() []byte](#PubKeyEd25519.Address)
* [func (pubKey PubKeyEd25519) Bytes() []byte](#PubKeyEd25519.Bytes)
* [func (pubKey PubKeyEd25519) Equals(other PubKey) bool](#PubKeyEd25519.Equals)
* [func (pubKey PubKeyEd25519) KeyString() string](#PubKeyEd25519.KeyString)
* [func (p PubKeyEd25519) MarshalJSON() ([]byte, error)](#PubKeyEd25519.MarshalJSON)
* [func (pubKey PubKeyEd25519) String() string](#PubKeyEd25519.String)
* [func (pubKey PubKeyEd25519) ToCurve25519() *[32]byte](#PubKeyEd25519.ToCurve25519)
* [func (p *PubKeyEd25519) UnmarshalJSON(enc []byte) error](#PubKeyEd25519.UnmarshalJSON)
* [func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ Signature) bool](#PubKeyEd25519.VerifyBytes)
* [type PubKeyS](#PubKeyS)
* [func (p PubKeyS) Empty() bool](#PubKeyS.Empty)
* [func (p PubKeyS) MarshalJSON() ([]byte, error)](#PubKeyS.MarshalJSON)
* [func (p *PubKeyS) UnmarshalJSON(data []byte) (err error)](#PubKeyS.UnmarshalJSON)
* [type PubKeySecp256k1](#PubKeySecp256k1)
* [func (pubKey PubKeySecp256k1) Address() []byte](#PubKeySecp256k1.Address)
* [func (pubKey PubKeySecp256k1) Bytes() []byte](#PubKeySecp256k1.Bytes)
* [func (pubKey PubKeySecp256k1) Equals(other PubKey) bool](#PubKeySecp256k1.Equals)
* [func (pubKey PubKeySecp256k1) KeyString() string](#PubKeySecp256k1.KeyString)
* [func (p PubKeySecp256k1) MarshalJSON() ([]byte, error)](#PubKeySecp256k1.MarshalJSON)
* [func (pubKey PubKeySecp256k1) String() string](#PubKeySecp256k1.String)
* [func (p *PubKeySecp256k1) UnmarshalJSON(enc []byte) error](#PubKeySecp256k1.UnmarshalJSON)
* [func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, sig_ Signature) bool](#PubKeySecp256k1.VerifyBytes)
* [type Signature](#Signature)
* [func SignatureFromBytes(sigBytes []byte) (sig Signature, err error)](#SignatureFromBytes)
* [type SignatureEd25519](#SignatureEd25519)
* [func (sig SignatureEd25519) Bytes() []byte](#SignatureEd25519.Bytes)
* [func (sig SignatureEd25519) Equals(other Signature) bool](#SignatureEd25519.Equals)
* [func (sig SignatureEd25519) IsZero() bool](#SignatureEd25519.IsZero)
* [func (p SignatureEd25519) MarshalJSON() ([]byte, error)](#SignatureEd25519.MarshalJSON)
* [func (sig SignatureEd25519) String() string](#SignatureEd25519.String)
* [func (p *SignatureEd25519) UnmarshalJSON(enc []byte) error](#SignatureEd25519.UnmarshalJSON)
* [type SignatureS](#SignatureS)
* [func (p SignatureS) Empty() bool](#SignatureS.Empty)
* [func (p SignatureS) MarshalJSON() ([]byte, error)](#SignatureS.MarshalJSON)
* [func (p *SignatureS) UnmarshalJSON(data []byte) (err error)](#SignatureS.UnmarshalJSON)
* [type SignatureSecp256k1](#SignatureSecp256k1)
* [func (sig SignatureSecp256k1) Bytes() []byte](#SignatureSecp256k1.Bytes)
* [func (sig SignatureSecp256k1) Equals(other Signature) bool](#SignatureSecp256k1.Equals)
* [func (sig SignatureSecp256k1) IsZero() bool](#SignatureSecp256k1.IsZero)
* [func (p SignatureSecp256k1) MarshalJSON() ([]byte, error)](#SignatureSecp256k1.MarshalJSON)
* [func (sig SignatureSecp256k1) String() string](#SignatureSecp256k1.String)
* [func (p *SignatureSecp256k1) UnmarshalJSON(enc []byte) error](#SignatureSecp256k1.UnmarshalJSON)
#### <a name="pkg-files">Package files</a>
[armor.go](/src/github.com/tendermint/go-crypto/armor.go) [hash.go](/src/github.com/tendermint/go-crypto/hash.go) [priv_key.go](/src/github.com/tendermint/go-crypto/priv_key.go) [pub_key.go](/src/github.com/tendermint/go-crypto/pub_key.go) [random.go](/src/github.com/tendermint/go-crypto/random.go) [signature.go](/src/github.com/tendermint/go-crypto/signature.go) [symmetric.go](/src/github.com/tendermint/go-crypto/symmetric.go)
## <a name="pkg-constants">Constants</a>
``` go
const (
TypeEd25519 = byte(0x01)
TypeSecp256k1 = byte(0x02)
NameEd25519 = "ed25519"
NameSecp256k1 = "secp256k1"
)
```
Types of implementations
## <a name="CRandBytes">func</a> [CRandBytes](/src/target/random.go?s=698:734#L28)
``` go
func CRandBytes(numBytes int) []byte
```
This uses the OS and the Seed(s).
## <a name="CRandHex">func</a> [CRandHex](/src/target/random.go?s=924:959#L38)
``` go
func CRandHex(numDigits int) string
```
RandHex(24) gives 96 bits of randomness, strong enough for most purposes.
## <a name="CReader">func</a> [CReader](/src/target/random.go?s=1078:1102#L43)
``` go
func CReader() io.Reader
```
Returns a crand.Reader mixed with user-supplied entropy
## <a name="DecodeArmor">func</a> [DecodeArmor](/src/target/armor.go?s=596:699#L18)
``` go
func DecodeArmor(armorStr string) (blockType string, headers map[string]string, data []byte, err error)
```
## <a name="DecryptSymmetric">func</a> [DecryptSymmetric](/src/target/symmetric.go?s=1048:1133#L23)
``` go
func DecryptSymmetric(ciphertext []byte, secret []byte) (plaintext []byte, err error)
```
secret must be 32 bytes long. Use something like Sha256(Bcrypt(passphrase))
The ciphertext is (secretbox.Overhead + 24) bytes longer than the plaintext.
## <a name="EncodeArmor">func</a> [EncodeArmor](/src/target/armor.go?s=125:206#L1)
``` go
func EncodeArmor(blockType string, headers map[string]string, data []byte) string
```
## <a name="EncryptSymmetric">func</a> [EncryptSymmetric](/src/target/symmetric.go?s=356:430#L6)
``` go
func EncryptSymmetric(plaintext []byte, secret []byte) (ciphertext []byte)
```
secret must be 32 bytes long. Use something like Sha256(Bcrypt(passphrase))
The ciphertext is (secretbox.Overhead + 24) bytes longer than the plaintext.
NOTE: call crypto.MixEntropy() first.
## <a name="MixEntropy">func</a> [MixEntropy](/src/target/random.go?s=407:440#L13)
``` go
func MixEntropy(seedBytes []byte)
```
Mix additional bytes of randomness, e.g. from hardware, user-input, etc.
It is OK to call it multiple times. It does not diminish security.
## <a name="Ripemd160">func</a> [Ripemd160](/src/target/hash.go?s=185:220#L4)
``` go
func Ripemd160(bytes []byte) []byte
```
## <a name="Sha256">func</a> [Sha256](/src/target/hash.go?s=78:110#L1)
``` go
func Sha256(bytes []byte) []byte
```
## <a name="PrivKey">type</a> [PrivKey](/src/target/priv_key.go?s=326:435#L5)
``` go
type PrivKey interface {
Bytes() []byte
Sign(msg []byte) Signature
PubKey() PubKey
Equals(PrivKey) bool
}
```
PrivKey is part of PrivAccount and state.PrivValidator.
### <a name="PrivKeyFromBytes">func</a> [PrivKeyFromBytes](/src/target/priv_key.go?s=1302:1373#L50)
``` go
func PrivKeyFromBytes(privKeyBytes []byte) (privKey PrivKey, err error)
```
## <a name="PrivKeyEd25519">type</a> [PrivKeyEd25519](/src/target/priv_key.go?s=1502:1530#L58)
``` go
type PrivKeyEd25519 [64]byte
```
Implements PrivKey
### <a name="GenPrivKeyEd25519">func</a> [GenPrivKeyEd25519](/src/target/priv_key.go?s=3003:3042#L116)
``` go
func GenPrivKeyEd25519() PrivKeyEd25519
```
### <a name="GenPrivKeyEd25519FromSecret">func</a> [GenPrivKeyEd25519FromSecret](/src/target/priv_key.go?s=3290:3352#L125)
``` go
func GenPrivKeyEd25519FromSecret(secret []byte) PrivKeyEd25519
```
NOTE: secret should be the output of a KDF like bcrypt,
if it's derived from user input.
### <a name="PrivKeyEd25519.Bytes">func</a> (PrivKeyEd25519) [Bytes](/src/target/priv_key.go?s=1532:1576#L60)
``` go
func (privKey PrivKeyEd25519) Bytes() []byte
```
### <a name="PrivKeyEd25519.Equals">func</a> (PrivKeyEd25519) [Equals](/src/target/priv_key.go?s=1973:2029#L75)
``` go
func (privKey PrivKeyEd25519) Equals(other PrivKey) bool
```
### <a name="PrivKeyEd25519.Generate">func</a> (PrivKeyEd25519) [Generate](/src/target/priv_key.go?s=2761:2825#L106)
``` go
func (privKey PrivKeyEd25519) Generate(index int) PrivKeyEd25519
```
Deterministically generates new priv-key bytes from key.
### <a name="PrivKeyEd25519.MarshalJSON">func</a> (PrivKeyEd25519) [MarshalJSON](/src/target/priv_key.go?s=2156:2209#L83)
``` go
func (p PrivKeyEd25519) MarshalJSON() ([]byte, error)
```
### <a name="PrivKeyEd25519.PubKey">func</a> (PrivKeyEd25519) [PubKey](/src/target/priv_key.go?s=1826:1871#L70)
``` go
func (privKey PrivKeyEd25519) PubKey() PubKey
```
### <a name="PrivKeyEd25519.Sign">func</a> (PrivKeyEd25519) [Sign](/src/target/priv_key.go?s=1635:1691#L64)
``` go
func (privKey PrivKeyEd25519) Sign(msg []byte) Signature
```
### <a name="PrivKeyEd25519.String">func</a> (PrivKeyEd25519) [String](/src/target/priv_key.go?s=2613:2658#L101)
``` go
func (privKey PrivKeyEd25519) String() string
```
### <a name="PrivKeyEd25519.ToCurve25519">func</a> (PrivKeyEd25519) [ToCurve25519](/src/target/priv_key.go?s=2399:2453#L94)
``` go
func (privKey PrivKeyEd25519) ToCurve25519() *[32]byte
```
### <a name="PrivKeyEd25519.UnmarshalJSON">func</a> (\*PrivKeyEd25519) [UnmarshalJSON](/src/target/priv_key.go?s=2250:2306#L87)
``` go
func (p *PrivKeyEd25519) UnmarshalJSON(enc []byte) error
```
## <a name="PrivKeyS">type</a> [PrivKeyS](/src/target/priv_key.go?s=929:962#L30)
``` go
type PrivKeyS struct {
PrivKey
}
```
PrivKeyS add json serialization to PrivKey
### <a name="PrivKeyS.Empty">func</a> (PrivKeyS) [Empty](/src/target/priv_key.go?s=1241:1271#L46)
``` go
func (p PrivKeyS) Empty() bool
```
### <a name="PrivKeyS.MarshalJSON">func</a> (PrivKeyS) [MarshalJSON](/src/target/priv_key.go?s=964:1011#L34)
``` go
func (p PrivKeyS) MarshalJSON() ([]byte, error)
```
### <a name="PrivKeyS.UnmarshalJSON">func</a> (\*PrivKeyS) [UnmarshalJSON](/src/target/priv_key.go?s=1057:1114#L38)
``` go
func (p *PrivKeyS) UnmarshalJSON(data []byte) (err error)
```
## <a name="PrivKeySecp256k1">type</a> [PrivKeySecp256k1](/src/target/priv_key.go?s=3635:3665#L136)
``` go
type PrivKeySecp256k1 [32]byte
```
Implements PrivKey
### <a name="GenPrivKeySecp256k1">func</a> [GenPrivKeySecp256k1](/src/target/priv_key.go?s=5071:5114#L194)
``` go
func GenPrivKeySecp256k1() PrivKeySecp256k1
```
### <a name="GenPrivKeySecp256k1FromSecret">func</a> [GenPrivKeySecp256k1FromSecret](/src/target/priv_key.go?s=5436:5502#L204)
``` go
func GenPrivKeySecp256k1FromSecret(secret []byte) PrivKeySecp256k1
```
NOTE: secret should be the output of a KDF like bcrypt,
if it's derived from user input.
### <a name="PrivKeySecp256k1.Bytes">func</a> (PrivKeySecp256k1) [Bytes](/src/target/priv_key.go?s=3667:3713#L138)
``` go
func (privKey PrivKeySecp256k1) Bytes() []byte
```
### <a name="PrivKeySecp256k1.Equals">func</a> (PrivKeySecp256k1) [Equals](/src/target/priv_key.go?s=4235:4293#L158)
``` go
func (privKey PrivKeySecp256k1) Equals(other PrivKey) bool
```
### <a name="PrivKeySecp256k1.MarshalJSON">func</a> (PrivKeySecp256k1) [MarshalJSON](/src/target/priv_key.go?s=4426:4481#L166)
``` go
func (p PrivKeySecp256k1) MarshalJSON() ([]byte, error)
```
### <a name="PrivKeySecp256k1.PubKey">func</a> (PrivKeySecp256k1) [PubKey](/src/target/priv_key.go?s=4032:4079#L151)
``` go
func (privKey PrivKeySecp256k1) PubKey() PubKey
```
### <a name="PrivKeySecp256k1.Sign">func</a> (PrivKeySecp256k1) [Sign](/src/target/priv_key.go?s=3772:3830#L142)
``` go
func (privKey PrivKeySecp256k1) Sign(msg []byte) Signature
```
### <a name="PrivKeySecp256k1.String">func</a> (PrivKeySecp256k1) [String](/src/target/priv_key.go?s=4673:4720#L177)
``` go
func (privKey PrivKeySecp256k1) String() string
```
### <a name="PrivKeySecp256k1.UnmarshalJSON">func</a> (\*PrivKeySecp256k1) [UnmarshalJSON](/src/target/priv_key.go?s=4522:4580#L170)
``` go
func (p *PrivKeySecp256k1) UnmarshalJSON(enc []byte) error
```
## <a name="PubKey">type</a> [PubKey](/src/target/pub_key.go?s=361:506#L7)
``` go
type PubKey interface {
Address() []byte
Bytes() []byte
KeyString() string
VerifyBytes(msg []byte, sig Signature) bool
Equals(PubKey) bool
}
```
PubKey is part of Account and Validator.
### <a name="PubKeyFromBytes">func</a> [PubKeyFromBytes](/src/target/pub_key.go?s=1203:1270#L45)
``` go
func PubKeyFromBytes(pubKeyBytes []byte) (pubKey PubKey, err error)
```
## <a name="PubKeyEd25519">type</a> [PubKeyEd25519](/src/target/pub_key.go?s=1396:1423#L53)
``` go
type PubKeyEd25519 [32]byte
```
Implements PubKey
### <a name="PubKeyEd25519.Address">func</a> (PubKeyEd25519) [Address](/src/target/pub_key.go?s=1425:1469#L55)
``` go
func (pubKey PubKeyEd25519) Address() []byte
```
### <a name="PubKeyEd25519.Bytes">func</a> (PubKeyEd25519) [Bytes](/src/target/pub_key.go?s=1789:1831#L68)
``` go
func (pubKey PubKeyEd25519) Bytes() []byte
```
### <a name="PubKeyEd25519.Equals">func</a> (PubKeyEd25519) [Equals](/src/target/pub_key.go?s=3064:3117#L119)
``` go
func (pubKey PubKeyEd25519) Equals(other PubKey) bool
```
### <a name="PubKeyEd25519.KeyString">func</a> (PubKeyEd25519) [KeyString](/src/target/pub_key.go?s=2983:3029#L115)
``` go
func (pubKey PubKeyEd25519) KeyString() string
```
Must return the full bytes in hex.
Used for map keying, etc.
### <a name="PubKeyEd25519.MarshalJSON">func</a> (PubKeyEd25519) [MarshalJSON](/src/target/pub_key.go?s=2279:2331#L87)
``` go
func (p PubKeyEd25519) MarshalJSON() ([]byte, error)
```
### <a name="PubKeyEd25519.String">func</a> (PubKeyEd25519) [String](/src/target/pub_key.go?s=2823:2866#L109)
``` go
func (pubKey PubKeyEd25519) String() string
```
### <a name="PubKeyEd25519.ToCurve25519">func</a> (PubKeyEd25519) [ToCurve25519](/src/target/pub_key.go?s=2585:2637#L100)
``` go
func (pubKey PubKeyEd25519) ToCurve25519() *[32]byte
```
For use with golang/crypto/nacl/box
If error, returns nil.
### <a name="PubKeyEd25519.UnmarshalJSON">func</a> (\*PubKeyEd25519) [UnmarshalJSON](/src/target/pub_key.go?s=2372:2427#L91)
``` go
func (p *PubKeyEd25519) UnmarshalJSON(enc []byte) error
```
### <a name="PubKeyEd25519.VerifyBytes">func</a> (PubKeyEd25519) [VerifyBytes](/src/target/pub_key.go?s=1888:1960#L72)
``` go
func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ Signature) bool
```
## <a name="PubKeyS">type</a> [PubKeyS](/src/target/pub_key.go?s=841:872#L25)
``` go
type PubKeyS struct {
PubKey
}
```
PubKeyS add json serialization to PubKey
### <a name="PubKeyS.Empty">func</a> (PubKeyS) [Empty](/src/target/pub_key.go?s=1144:1173#L41)
``` go
func (p PubKeyS) Empty() bool
```
### <a name="PubKeyS.MarshalJSON">func</a> (PubKeyS) [MarshalJSON](/src/target/pub_key.go?s=874:920#L29)
``` go
func (p PubKeyS) MarshalJSON() ([]byte, error)
```
### <a name="PubKeyS.UnmarshalJSON">func</a> (\*PubKeyS) [UnmarshalJSON](/src/target/pub_key.go?s=964:1020#L33)
``` go
func (p *PubKeyS) UnmarshalJSON(data []byte) (err error)
```
## <a name="PubKeySecp256k1">type</a> [PubKeySecp256k1](/src/target/pub_key.go?s=3401:3430#L132)
``` go
type PubKeySecp256k1 [33]byte
```
Implements PubKey.
Compressed pubkey (just the x-cord),
prefixed with 0x02 or 0x03, depending on the y-cord.
### <a name="PubKeySecp256k1.Address">func</a> (PubKeySecp256k1) [Address](/src/target/pub_key.go?s=3497:3543#L135)
``` go
func (pubKey PubKeySecp256k1) Address() []byte
```
Implements Bitcoin style addresses: RIPEMD160(SHA256(pubkey))
### <a name="PubKeySecp256k1.Bytes">func</a> (PubKeySecp256k1) [Bytes](/src/target/pub_key.go?s=3774:3818#L145)
``` go
func (pubKey PubKeySecp256k1) Bytes() []byte
```
### <a name="PubKeySecp256k1.Equals">func</a> (PubKeySecp256k1) [Equals](/src/target/pub_key.go?s=4897:4952#L192)
``` go
func (pubKey PubKeySecp256k1) Equals(other PubKey) bool
```
### <a name="PubKeySecp256k1.KeyString">func</a> (PubKeySecp256k1) [KeyString](/src/target/pub_key.go?s=4814:4862#L188)
``` go
func (pubKey PubKeySecp256k1) KeyString() string
```
Must return the full bytes in hex.
Used for map keying, etc.
### <a name="PubKeySecp256k1.MarshalJSON">func</a> (PubKeySecp256k1) [MarshalJSON](/src/target/pub_key.go?s=4405:4459#L171)
``` go
func (p PubKeySecp256k1) MarshalJSON() ([]byte, error)
```
### <a name="PubKeySecp256k1.String">func</a> (PubKeySecp256k1) [String](/src/target/pub_key.go?s=4650:4695#L182)
``` go
func (pubKey PubKeySecp256k1) String() string
```
### <a name="PubKeySecp256k1.UnmarshalJSON">func</a> (\*PubKeySecp256k1) [UnmarshalJSON](/src/target/pub_key.go?s=4500:4557#L175)
``` go
func (p *PubKeySecp256k1) UnmarshalJSON(enc []byte) error
```
### <a name="PubKeySecp256k1.VerifyBytes">func</a> (PubKeySecp256k1) [VerifyBytes](/src/target/pub_key.go?s=3875:3949#L149)
``` go
func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, sig_ Signature) bool
```
## <a name="Signature">type</a> [Signature](/src/target/signature.go?s=204:304#L3)
``` go
type Signature interface {
Bytes() []byte
IsZero() bool
String() string
Equals(Signature) bool
}
```
Signature is a part of Txs and consensus Votes.
### <a name="SignatureFromBytes">func</a> [SignatureFromBytes](/src/target/signature.go?s=1031:1098#L40)
``` go
func SignatureFromBytes(sigBytes []byte) (sig Signature, err error)
```
## <a name="SignatureEd25519">type</a> [SignatureEd25519](/src/target/signature.go?s=1221:1251#L48)
``` go
type SignatureEd25519 [64]byte
```
Implements Signature
### <a name="SignatureEd25519.Bytes">func</a> (SignatureEd25519) [Bytes](/src/target/signature.go?s=1253:1295#L50)
``` go
func (sig SignatureEd25519) Bytes() []byte
```
### <a name="SignatureEd25519.Equals">func</a> (SignatureEd25519) [Equals](/src/target/signature.go?s=1520:1576#L58)
``` go
func (sig SignatureEd25519) Equals(other Signature) bool
```
### <a name="SignatureEd25519.IsZero">func</a> (SignatureEd25519) [IsZero](/src/target/signature.go?s=1352:1393#L54)
``` go
func (sig SignatureEd25519) IsZero() bool
```
### <a name="SignatureEd25519.MarshalJSON">func</a> (SignatureEd25519) [MarshalJSON](/src/target/signature.go?s=1701:1756#L66)
``` go
func (p SignatureEd25519) MarshalJSON() ([]byte, error)
```
### <a name="SignatureEd25519.String">func</a> (SignatureEd25519) [String](/src/target/signature.go?s=1420:1463#L56)
``` go
func (sig SignatureEd25519) String() string
```
### <a name="SignatureEd25519.UnmarshalJSON">func</a> (\*SignatureEd25519) [UnmarshalJSON](/src/target/signature.go?s=1797:1855#L70)
``` go
func (p *SignatureEd25519) UnmarshalJSON(enc []byte) error
```
## <a name="SignatureS">type</a> [SignatureS](/src/target/signature.go?s=648:685#L20)
``` go
type SignatureS struct {
Signature
}
```
SignatureS add json serialization to Signature
### <a name="SignatureS.Empty">func</a> (SignatureS) [Empty](/src/target/signature.go?s=966:998#L36)
``` go
func (p SignatureS) Empty() bool
```
### <a name="SignatureS.MarshalJSON">func</a> (SignatureS) [MarshalJSON](/src/target/signature.go?s=687:736#L24)
``` go
func (p SignatureS) MarshalJSON() ([]byte, error)
```
### <a name="SignatureS.UnmarshalJSON">func</a> (\*SignatureS) [UnmarshalJSON](/src/target/signature.go?s=780:839#L28)
``` go
func (p *SignatureS) UnmarshalJSON(data []byte) (err error)
```
## <a name="SignatureSecp256k1">type</a> [SignatureSecp256k1](/src/target/signature.go?s=2013:2043#L80)
``` go
type SignatureSecp256k1 []byte
```
Implements Signature
### <a name="SignatureSecp256k1.Bytes">func</a> (SignatureSecp256k1) [Bytes](/src/target/signature.go?s=2045:2089#L82)
``` go
func (sig SignatureSecp256k1) Bytes() []byte
```
### <a name="SignatureSecp256k1.Equals">func</a> (SignatureSecp256k1) [Equals](/src/target/signature.go?s=2318:2376#L90)
``` go
func (sig SignatureSecp256k1) Equals(other Signature) bool
```
### <a name="SignatureSecp256k1.IsZero">func</a> (SignatureSecp256k1) [IsZero](/src/target/signature.go?s=2146:2189#L86)
``` go
func (sig SignatureSecp256k1) IsZero() bool
```
### <a name="SignatureSecp256k1.MarshalJSON">func</a> (SignatureSecp256k1) [MarshalJSON](/src/target/signature.go?s=2502:2559#L97)
``` go
func (p SignatureSecp256k1) MarshalJSON() ([]byte, error)
```
### <a name="SignatureSecp256k1.String">func</a> (SignatureSecp256k1) [String](/src/target/signature.go?s=2216:2261#L88)
``` go
func (sig SignatureSecp256k1) String() string
```
### <a name="SignatureSecp256k1.UnmarshalJSON">func</a> (\*SignatureSecp256k1) [UnmarshalJSON](/src/target/signature.go?s=2597:2657#L101)
``` go
func (p *SignatureSecp256k1) UnmarshalJSON(enc []byte) error
```
- - -
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)
## Importing it
`import "github.com/tendermint/go-crypto"`

+ 0
- 117
cmd/README.md View File

@ -1,117 +0,0 @@
# Keys CLI
This is as much an example how to expose cobra/viper, as for a cli itself
(I think this code is overkill for what go-keys needs). But please look at
the commands, and give feedback and changes.
`RootCmd` calls some initialization functions (`cobra.OnInitialize` and `RootCmd.PersistentPreRunE`) which serve to connect environmental variables and cobra flags, as well as load the config file. It also validates the flags registered on root and creates the cryptomanager, which will be used by all subcommands.
## Help info
```
# keys help
Keys allows you to manage your local keystore for tendermint.
These keys may be in any format supported by go-crypto and can be
used by light-clients, full nodes, or any other application that
needs to sign with a private key.
Usage:
keys [command]
Available Commands:
get Get details of one key
list List all keys
new Create a new public/private key pair
serve Run the key manager as an http server
update Change the password for a private key
Flags:
--keydir string Directory to store private keys (subdir of root) (default "keys")
-o, --output string Output format (text|json) (default "text")
-r, --root string root directory for config and data (default "/Users/ethan/.tlc")
Use "keys [command] --help" for more information about a command.
```
## Getting the config file
The first step is to load in root, by checking the following in order:
* -r, --root command line flag
* TM_ROOT environmental variable
* default ($HOME/.tlc evaluated at runtime)
Once the `rootDir` is established, the script looks for a config file named `keys.{json,toml,yaml,hcl}` in that directory and parses it. These values will provide defaults for flags of the same name.
There is an example config file for testing out locally, which writes keys to `./.mykeys`. You can
## Getting/Setting variables
When we want to get the value of a user-defined variable (eg. `output`), we can call `viper.GetString("output")`, which will do the following checks, until it finds a match:
* Is `--output` command line flag present?
* Is `TM_OUTPUT` environmental variable set?
* Was a config file found and does it have an `output` variable?
* Is there a default set on the command line flag?
If no variable is set and there was no default, we get back "".
This setup allows us to have powerful command line flags, but use env variables or config files (local or 12-factor style) to avoid passing these arguments every time.
## Nesting structures
Sometimes we don't just need key-value pairs, but actually a multi-level config file, like
```
[mail]
from = "no-reply@example.com"
server = "mail.example.com"
port = 567
password = "XXXXXX"
```
This CLI is too simple to warant such a structure, but I think eg. tendermint could benefit from such an approach. Here are some pointers:
* [Accessing nested keys from config files](https://github.com/spf13/viper#accessing-nested-keys)
* [Overriding nested values with envvars](https://www.netlify.com/blog/2016/09/06/creating-a-microservice-boilerplate-in-go/#nested-config-values) - the mentioned outstanding PR is already merged into master!
* Overriding nested values with cli flags? (use `--log_config.level=info` ??)
I'd love to see an example of this fully worked out in a more complex CLI.
## Have your cake and eat it too
It's easy to render data different ways. Some better for viewing, some better for importing to other programs. You can just add some global (persistent) flags to control the output formatting, and everyone gets what they want.
```
# keys list -e hex
All keys:
betty d0789984492b1674e276b590d56b7ae077f81adc
john b77f4720b220d1411a649b6c7f1151eb6b1c226a
# keys list -e btc
All keys:
betty 3uTF4r29CbtnzsNHZoPSYsE4BDwH
john 3ZGp2Md35iw4XVtRvZDUaAEkCUZP
# keys list -e b64 -o json
[
{
"name": "betty",
"address": "0HiZhEkrFnTidrWQ1Wt64Hf4Gtw=",
"pubkey": {
"type": "secp256k1",
"data": "F83WvhT0KwttSoqQqd_0_r2ztUUaQix5EXdO8AZyREoV31Og780NW59HsqTAb2O4hZ-w-j0Z-4b2IjfdqqfhVQ=="
}
},
{
"name": "john",
"address": "t39HILIg0UEaZJtsfxFR62scImo=",
"pubkey": {
"type": "ed25519",
"data": "t1LFmbg_8UTwj-n1wkqmnTp6NfaOivokEhlYySlGYCY="
}
}
]
```

+ 0
- 49
cmd/delete.go View File

@ -1,49 +0,0 @@
// Copyright © 2017 Ethan Frey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
// deleteCmd represents the delete command
var deleteCmd = &cobra.Command{
Use: "delete [name]",
Short: "DANGER: Delete a private key from your system",
RunE: runDeleteCmd,
}
func runDeleteCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 || len(args[0]) == 0 {
return errors.New("You must provide a name for the key")
}
name := args[0]
oldpass, err := getPassword("DANGER - enter password to permanently delete key:")
if err != nil {
return err
}
err = GetKeyManager().Delete(name, oldpass)
if err != nil {
return err
}
fmt.Println("Password deleted forever (uh oh!)")
return nil
}

+ 0
- 42
cmd/get.go View File

@ -1,42 +0,0 @@
// Copyright © 2017 Ethan Frey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
// getCmd represents the get command
var getCmd = &cobra.Command{
Use: "get [name]",
Short: "Get details of one key",
Long: `Return public details of one local key.`,
RunE: runGetCmd,
}
func runGetCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 || len(args[0]) == 0 {
return errors.New("You must provide a name for the key")
}
name := args[0]
info, err := GetKeyManager().Get(name)
if err == nil {
printInfo(info)
}
return err
}

+ 0
- 30
cmd/keys/main.go View File

@ -1,30 +0,0 @@
// Copyright © 2017 Ethan Frey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"os"
"github.com/tendermint/go-crypto/cmd"
"github.com/tendermint/tmlibs/cli"
)
func main() {
// for demos, we enable the key server, probably don't want this
// in most binaries we embed the key management into
cmd.RegisterServer()
root := cli.PrepareMainCmd(cmd.RootCmd, "TM", os.ExpandEnv("$HOME/.tlc"))
root.Execute()
}

+ 0
- 34
cmd/list.go View File

@ -1,34 +0,0 @@
// Copyright © 2017 Ethan Frey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import "github.com/spf13/cobra"
// listCmd represents the list command
var listCmd = &cobra.Command{
Use: "list",
Short: "List all keys",
Long: `Return a list of all public keys stored by this key manager
along with their associated name and address.`,
RunE: runListCmd,
}
func runListCmd(cmd *cobra.Command, args []string) error {
infos, err := GetKeyManager().List()
if err == nil {
printInfos(infos)
}
return err
}

+ 0
- 94
cmd/new.go View File

@ -1,94 +0,0 @@
// Copyright © 2017 Ethan Frey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"github.com/pkg/errors"
"github.com/tendermint/go-crypto/keys"
"github.com/tendermint/go-wire/data"
"github.com/tendermint/tmlibs/cli"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const (
flagType = "type"
flagNoBackup = "no-backup"
)
// newCmd represents the new command
var newCmd = &cobra.Command{
Use: "new [name]",
Short: "Create a new public/private key pair",
Long: `Add a public/private key pair to the key store.
The password muts be entered in the terminal and not
passed as a command line argument for security.`,
RunE: runNewCmd,
}
func init() {
newCmd.Flags().StringP(flagType, "t", "ed25519", "Type of key (ed25519|secp256k1)")
newCmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)")
}
func runNewCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 || len(args[0]) == 0 {
return errors.New("You must provide a name for the key")
}
name := args[0]
algo := viper.GetString(flagType)
pass, err := getCheckPassword("Enter a passphrase:", "Repeat the passphrase:")
if err != nil {
return err
}
info, seed, err := GetKeyManager().Create(name, pass, algo)
if err == nil {
printCreate(info, seed)
}
return err
}
type NewOutput struct {
Key keys.Info `json:"key"`
Seed string `json:"seed"`
}
func printCreate(info keys.Info, seed string) {
switch viper.Get(cli.OutputFlag) {
case "text":
printInfo(info)
// print seed unless requested not to.
if !viper.GetBool(flagNoBackup) {
fmt.Println("**Important** write this seed phrase in a safe place.")
fmt.Println("It is the only way to recover your account if you ever forget your password.\n")
fmt.Println(seed)
}
case "json":
out := NewOutput{Key: info}
if !viper.GetBool(flagNoBackup) {
out.Seed = seed
}
json, err := data.ToJSON(out)
if err != nil {
panic(err) // really shouldn't happen...
}
fmt.Println(string(json))
}
}

+ 0
- 61
cmd/recover.go View File

@ -1,61 +0,0 @@
// Copyright © 2017 Ethan Frey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
// recoverCmd represents the recover command
var recoverCmd = &cobra.Command{
Use: "recover [name]",
Short: "Recover a private key from a seed phrase",
Long: `Recover a private key from a seed phrase.
I really hope you wrote this down when you created the new key.
The seed is only displayed on creation, never again.
You can also use this to copy a key between multiple testnets,
simply by "recovering" the key in the other nets you want to copy
to. Of course, it has no coins on the other nets, just the same address.`,
RunE: runRecoverCmd,
}
func runRecoverCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 || len(args[0]) == 0 {
return errors.New("You must provide a name for the key")
}
name := args[0]
pass, err := getPassword("Enter the new passphrase:")
if err != nil {
return err
}
// not really a password... huh?
seed, err := getSeed("Enter your recovery seed phrase:")
if err != nil {
return err
}
info, err := GetKeyManager().Recover(name, pass, seed)
if err != nil {
return err
}
printInfo(info)
return nil
}

+ 0
- 50
cmd/root.go View File

@ -1,50 +0,0 @@
// Copyright © 2017 Ethan Frey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"github.com/spf13/cobra"
keys "github.com/tendermint/go-crypto/keys"
)
const KeySubdir = "keys"
var (
manager keys.Manager
)
// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "keys",
Short: "Key manager for tendermint clients",
Long: `Keys allows you to manage your local keystore for tendermint.
These keys may be in any format supported by go-crypto and can be
used by light-clients, full nodes, or any other application that
needs to sign with a private key.`,
}
func init() {
RootCmd.AddCommand(getCmd)
RootCmd.AddCommand(listCmd)
RootCmd.AddCommand(newCmd)
RootCmd.AddCommand(updateCmd)
RootCmd.AddCommand(deleteCmd)
RootCmd.AddCommand(recoverCmd)
}
func RegisterServer() {
RootCmd.AddCommand(serveCmd)
}

+ 0
- 110
cmd/serve.go View File

@ -1,110 +0,0 @@
// Copyright © 2017 Ethan Frey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"net"
"net/http"
"os"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/go-crypto/keys/server"
)
const (
flagPort = "port"
flagSocket = "socket"
)
// serveCmd represents the serve command
var serveCmd = &cobra.Command{
Use: "serve",
Short: "Run the key manager as an http server",
Long: `Launch an http server with a rest api to manage the
private keys much more in depth than the cli can perform.
In particular, this will allow you to sign transactions with
the private keys in the store.`,
RunE: runServeCmd,
}
func init() {
serveCmd.Flags().IntP(flagPort, "p", 8118, "TCP Port for listen for http server")
serveCmd.Flags().StringP(flagSocket, "s", "", "UNIX socket for more secure http server")
serveCmd.Flags().StringP(flagType, "t", "ed25519", "Default key type (ed25519|secp256k1)")
}
func runServeCmd(cmd *cobra.Command, args []string) error {
var l net.Listener
var err error
socket := viper.GetString(flagSocket)
if socket != "" {
l, err = createSocket(socket)
if err != nil {
return errors.Wrap(err, "Cannot create socket")
}
} else {
port := viper.GetInt(flagPort)
l, err = net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
return errors.Errorf("Cannot listen on port %d", port)
}
}
router := mux.NewRouter()
ks := server.New(GetKeyManager(), viper.GetString(flagType))
ks.Register(router)
// only set cors for tcp listener
var h http.Handler
if socket == "" {
allowedHeaders := handlers.AllowedHeaders([]string{"Content-Type"})
h = handlers.CORS(allowedHeaders)(router)
} else {
h = router
}
err = http.Serve(l, h)
fmt.Printf("Server Killed: %+v\n", err)
return nil
}
// createSocket deletes existing socket if there, creates a new one,
// starts a server on the socket, and sets permissions to 0600
func createSocket(socket string) (net.Listener, error) {
err := os.Remove(socket)
if err != nil && !os.IsNotExist(err) {
// only fail if it does exist and cannot be deleted
return nil, err
}
l, err := net.Listen("unix", socket)
if err != nil {
return nil, err
}
mode := os.FileMode(0700) | os.ModeSocket
err = os.Chmod(socket, mode)
if err != nil {
l.Close()
return nil, err
}
return l, nil
}

+ 0
- 53
cmd/update.go View File

@ -1,53 +0,0 @@
// Copyright © 2017 Ethan Frey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
// updateCmd represents the update command
var updateCmd = &cobra.Command{
Use: "update [name]",
Short: "Change the password for a private key",
RunE: runUpdateCmd,
}
func runUpdateCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 || len(args[0]) == 0 {
return errors.New("You must provide a name for the key")
}
name := args[0]
oldpass, err := getPassword("Enter the current passphrase:")
if err != nil {
return err
}
newpass, err := getCheckPassword("Enter the new passphrase:", "Repeat the new passphrase:")
if err != nil {
return err
}
err = GetKeyManager().Update(name, oldpass, newpass)
if err != nil {
return err
}
fmt.Println("Password successfully updated!")
return nil
}

+ 0
- 144
cmd/utils.go View File

@ -1,144 +0,0 @@
package cmd
import (
"bufio"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/bgentry/speakeasy"
"github.com/mattn/go-isatty"
"github.com/pkg/errors"
"github.com/spf13/viper"
data "github.com/tendermint/go-wire/data"
"github.com/tendermint/tmlibs/cli"
keys "github.com/tendermint/go-crypto/keys"
"github.com/tendermint/go-crypto/keys/cryptostore"
"github.com/tendermint/go-crypto/keys/storage/filestorage"
)
const MinPassLength = 10
// GetKeyManager initializes a key manager based on the configuration
func GetKeyManager() keys.Manager {
if manager == nil {
// store the keys directory
rootDir := viper.GetString(cli.HomeFlag)
keyDir := filepath.Join(rootDir, KeySubdir)
// TODO: smarter loading??? with language and fallback?
codec := keys.MustLoadCodec("english")
// and construct the key manager
manager = cryptostore.New(
cryptostore.SecretBox,
filestorage.New(keyDir),
codec,
)
}
return manager
}
// if we read from non-tty, we just need to init the buffer reader once,
// in case we try to read multiple passwords (eg. update)
var buf *bufio.Reader
func inputIsTty() bool {
return isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd())
}
func stdinPassword() (string, error) {
if buf == nil {
buf = bufio.NewReader(os.Stdin)
}
pass, err := buf.ReadString('\n')
if err != nil {
return "", err
}
return strings.TrimSpace(pass), nil
}
func getPassword(prompt string) (pass string, err error) {
if inputIsTty() {
pass, err = speakeasy.Ask(prompt)
} else {
pass, err = stdinPassword()
}
if err != nil {
return "", err
}
if len(pass) < MinPassLength {
return "", errors.Errorf("Password must be at least %d characters", MinPassLength)
}
return pass, nil
}
func getSeed(prompt string) (seed string, err error) {
if inputIsTty() {
fmt.Println(prompt)
}
seed, err = stdinPassword()
seed = strings.TrimSpace(seed)
return
}
func getCheckPassword(prompt, prompt2 string) (string, error) {
// simple read on no-tty
if !inputIsTty() {
return getPassword(prompt)
}
// TODO: own function???
pass, err := getPassword(prompt)
if err != nil {
return "", err
}
pass2, err := getPassword(prompt2)
if err != nil {
return "", err
}
if pass != pass2 {
return "", errors.New("Passphrases don't match")
}
return pass, nil
}
func printInfo(info keys.Info) {
switch viper.Get(cli.OutputFlag) {
case "text":
addr, err := data.ToText(info.Address)
if err != nil {
panic(err) // really shouldn't happen...
}
sep := "\t\t"
if len(info.Name) > 7 {
sep = "\t"
}
fmt.Printf("%s%s%s\n", info.Name, sep, addr)
case "json":
json, err := data.ToJSON(info)
if err != nil {
panic(err) // really shouldn't happen...
}
fmt.Println(string(json))
}
}
func printInfos(infos keys.Infos) {
switch viper.Get(cli.OutputFlag) {
case "text":
fmt.Println("All keys:")
for _, i := range infos {
printInfo(i)
}
case "json":
json, err := data.ToJSON(infos)
if err != nil {
panic(err) // really shouldn't happen...
}
fmt.Println(string(json))
}
}

+ 20
- 59
glide.lock View File

@ -1,5 +1,5 @@
hash: 3bcee9fbccf29d21217b24b6a83ec51e1514f37b2ae5d8718cf6c5df80f4fb2c
updated: 2017-06-19T17:16:58.037568333+02:00
hash: c0a2db1b80c6b1b8aab31c526ce43e22e49b23c893c78b8fdb8546aa2e7b7cc6
updated: 2017-09-22T10:21:34.220901552-04:00
imports:
- name: github.com/bgentry/speakeasy
version: 4aabc24848ce5fd31929f7d1e4ea74d3709c14cd
@ -11,14 +11,16 @@ imports:
- chaincfg/chainhash
- wire
- name: github.com/btcsuite/btcutil
version: 66871daeb12123ece012a9628d2798d01195c4b3
version: 86346b5a958c0cf94186b87855469ae991be501c
subpackages:
- base58
- hdkeychain
- name: github.com/btcsuite/fastsha256
version: 637e656429416087660c84436a2a035d69d54e2e
- name: github.com/fsnotify/fsnotify
version: 4da3e2cfbabc9f751898f250b49f2439785783a1
- name: github.com/btcsuite/golangcrypto
version: 53f62d9b43e87a6c56975cf862af7edf33a8d0df
subpackages:
- ripemd160
- name: github.com/go-kit/kit
version: d67bb4c202e3b91377d1079b110a6c9ce23ab2f8
subpackages:
@ -38,48 +40,17 @@ imports:
- name: github.com/gorilla/context
version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42
- name: github.com/gorilla/handlers
version: 3a5767ca75ece5f7f1440b1d16975247f8d8b221
version: a4043c62cc2329bacda331d33fc908ab11ef0ec3
- name: github.com/gorilla/mux
version: 392c28fe23e1c45ddba891b0320b3b5df220beea
- name: github.com/hashicorp/hcl
version: a4b07c25de5ff55ad3b8936cea69a79a3d95a855
subpackages:
- hcl/ast
- hcl/parser
- hcl/scanner
- hcl/strconv
- hcl/token
- json/parser
- json/scanner
- json/token
- name: github.com/inconshreveable/mousetrap
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
version: bcd8bc72b08df0f70df986b97f95590779502d31
- name: github.com/howeyc/crc16
version: 96a97a1abb579c7ff1a8ffa77f2e72d1c314b57f
- name: github.com/kr/logfmt
version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0
- name: github.com/magiconair/properties
version: 51463bfca2576e06c62a8504b5c0f06d61312647
- name: github.com/mattn/go-isatty
version: 9622e0cc9d8f9be434ca605520ff9a16808fee47
- name: github.com/mitchellh/mapstructure
version: cc8532a8e9a55ea36402aa21efdf403a60d34096
- name: github.com/pelletier/go-buffruneio
version: c37440a7cf42ac63b919c752ca73a85067e05992
- name: github.com/pelletier/go-toml
version: 13d49d4606eb801b8f01ae542b4afc4c6ee3d84a
- name: github.com/pkg/errors
version: ff09b135c25aae272398c51a07235b90a75aa4f0
- name: github.com/spf13/afero
version: 9be650865eab0c12963d8753212f4f9c66cdcf12
subpackages:
- mem
- name: github.com/spf13/cast
version: acbeb36b902d72a7a4c18e8f3241075e7ab763e4
version: 645ef00459ed84a119197bfb8d8205042c6df63d
- name: github.com/spf13/cobra
version: db6b9a8b3f3f400c8ecb4a4d7d02245b8facad66
- name: github.com/spf13/jwalterweatherman
version: fa7ca7e836cf3a8bb4ebf799f472c12d7e903d66
- name: github.com/spf13/pflag
version: 80fe0fb4eba54167e2ccae1c6c950e72abf61b73
version: 4cdb38c072b86bf795d2c81de50784d9fdd6eb77
- name: github.com/spf13/viper
version: 0967fc9aceab2ce9da34061253ac10fb99bba5b2
- name: github.com/tendermint/ed25519
@ -93,9 +64,8 @@ imports:
- data
- data/base58
- name: github.com/tendermint/tmlibs
version: bd9d0d1637dadf1330e167189d5e5031aadcda6f
version: bffe6744ec277d60f707ab442e25513617842f8e
subpackages:
- cli
- common
- log
- name: golang.org/x/crypto
@ -110,26 +80,17 @@ imports:
- poly1305
- ripemd160
- salsa20/salsa
- name: golang.org/x/sys
version: 9ccfe848b9db8435a24c424abbc07a921adf1df5
subpackages:
- unix
- name: golang.org/x/text
version: 470f45bf29f4147d6fbd7dfd0a02a848e49f5bf4
subpackages:
- transform
- unicode/norm
- name: gopkg.in/go-playground/validator.v9
version: 6d8c18553ea1ac493d049edd6f102f52e618f085
- name: gopkg.in/yaml.v2
version: cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b
version: d529ee1b0f30352444f507cc6cdac96bfd12decc
testImports:
- name: github.com/cmars/basen
version: fe3947df716ebfda9847eb1b9a48f9592e06478c
- name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
subpackages:
- spew
- name: github.com/FactomProject/basen
version: fe3947df716ebfda9847eb1b9a48f9592e06478c
- name: github.com/FactomProject/btcutilecc
version: d3a63a5752ecf3fbc06bd97365da752111c263df
- name: github.com/mndrix/btcutil
version: d3a63a5752ecf3fbc06bd97365da752111c263df
- name: github.com/pmezard/go-difflib
@ -142,6 +103,6 @@ testImports:
- assert
- require
- name: github.com/tyler-smith/go-bip32
version: eb790af526c30f23a7c8b00a48e342f9d0bd6386
version: 2c9cfd17756470a0b7c3e4b7954bae7d11035504
- name: github.com/tyler-smith/go-bip39
version: 8e7a99b3e716f36d3b080a9a70f9eb45abe4edcc

+ 1
- 0
glide.yaml View File

@ -29,6 +29,7 @@ import:
- package: github.com/spf13/cobra
- package: github.com/spf13/viper
- package: gopkg.in/go-playground/validator.v9
- package: github.com/howeyc/crc16
testImport:
- package: github.com/mndrix/btcutil
- package: github.com/stretchr/testify


+ 14
- 3
hd/address.go View File

@ -282,9 +282,20 @@ func CalcSha512(buf []byte) []byte {
}
func ReverseBytes(buf []byte) []byte {
res := []byte{}
for i := len(buf) - 1; i >= 0; i-- {
res = append(res, buf[i])
var res []byte
if len(buf) == 0 {
return res
}
// Walk till mid-way, swapping bytes from each end:
// b[i] and b[len-i-1]
blen := len(buf)
res = make([]byte, blen)
mid := blen / 2
for left := 0; left <= mid; left++ {
right := blen - left - 1
res[left] = buf[right]
res[right] = buf[left]
}
return res
}

+ 53
- 0
hd/hd_test.go View File

@ -89,6 +89,26 @@ func TestHDToAddr(t *testing.T) {
}
}
func TestReverseBytes(t *testing.T) {
tests := [...]struct {
v []byte
want []byte
}{
{[]byte(""), []byte("")},
{nil, nil},
{[]byte("Tendermint"), []byte("tnimredneT")},
{[]byte("T"), []byte("T")},
{[]byte("Te"), []byte("eT")},
}
for i, tt := range tests {
got := ReverseBytes(tt.v)
if !bytes.Equal(got, tt.want) {
t.Errorf("#%d:\ngot= (%x)\nwant=(%x)", i, got, tt.want)
}
}
}
func ifExit(err error, n int) {
if err != nil {
fmt.Println(n, err)
@ -187,3 +207,36 @@ func tylerSmith(seed []byte) ([]byte, []byte, []byte) {
pub := k.PublicKey().Key
return masterKey.Key, priv, pub
}
// Benchmarks
var revBytesCases = [][]byte{
nil,
[]byte(""),
[]byte("12"),
// 16byte case
[]byte("abcdefghijklmnop"),
// 32byte case
[]byte("abcdefghijklmnopqrstuvwxyz123456"),
// 64byte case
[]byte("abcdefghijklmnopqrstuvwxyz123456abcdefghijklmnopqrstuvwxyz123456"),
}
func BenchmarkReverseBytes(b *testing.B) {
var sink []byte
for i := 0; i < b.N; i++ {
for _, tt := range revBytesCases {
sink = ReverseBytes(tt)
}
}
b.ReportAllocs()
// sink is necessary to ensure if the compiler tries
// to smart, that it won't optimize away the benchmarks.
if sink != nil {
}
}

+ 12
- 6
keys/cryptostore/encoder.go View File

@ -28,18 +28,24 @@ func secret(passphrase string) []byte {
type secretbox struct{}
func (e secretbox) Encrypt(key crypto.PrivKey, pass string) ([]byte, error) {
if pass == "" {
return key.Bytes(), nil
}
s := secret(pass)
cipher := crypto.EncryptSymmetric(key.Bytes(), s)
return cipher, nil
}
func (e secretbox) Decrypt(data []byte, pass string) (crypto.PrivKey, error) {
s := secret(pass)
private, err := crypto.DecryptSymmetric(data, s)
if err != nil {
return crypto.PrivKey{}, errors.Wrap(err, "Invalid Passphrase")
func (e secretbox) Decrypt(data []byte, pass string) (key crypto.PrivKey, err error) {
private := data
if pass != "" {
s := secret(pass)
private, err = crypto.DecryptSymmetric(data, s)
if err != nil {
return crypto.PrivKey{}, errors.Wrap(err, "Invalid Passphrase")
}
}
key, err := crypto.PrivKeyFromBytes(private)
key, err = crypto.PrivKeyFromBytes(private)
return key, errors.Wrap(err, "Invalid Passphrase")
}


+ 45
- 3
keys/cryptostore/encoder_test.go View File

@ -5,6 +5,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/go-crypto/keys/cryptostore"
)
@ -12,8 +15,8 @@ func TestNoopEncoder(t *testing.T) {
assert, require := assert.New(t), require.New(t)
noop := cryptostore.Noop
key := cryptostore.GenEd25519.Generate()
key2 := cryptostore.GenSecp256k1.Generate()
key := cryptostore.GenEd25519.Generate(cmn.RandBytes(16))
key2 := cryptostore.GenSecp256k1.Generate(cmn.RandBytes(16))
b, err := noop.Encrypt(key, "encode")
require.Nil(err)
@ -40,7 +43,7 @@ func TestSecretBox(t *testing.T) {
assert, require := assert.New(t), require.New(t)
enc := cryptostore.SecretBox
key := cryptostore.GenEd25519.Generate()
key := cryptostore.GenEd25519.Generate(cmn.RandBytes(16))
pass := "some-special-secret"
b, err := enc.Encrypt(key, pass)
@ -57,3 +60,42 @@ func TestSecretBox(t *testing.T) {
require.Nil(err)
assert.Equal(key, pk)
}
func TestSecretBoxNoPass(t *testing.T) {
assert, require := assert.New(t), require.New(t)
enc := cryptostore.SecretBox
key := cryptostore.GenEd25519.Generate(cmn.RandBytes(16))
cases := []struct {
encode string
decode string
valid bool
}{
{"foo", "foo", true},
{"foo", "food", false},
{"", "", true},
{"", "a", false},
{"a", "", false},
}
for i, tc := range cases {
b, err := enc.Encrypt(key, tc.encode)
require.Nil(err, "%d: %+v", i, err)
assert.NotEmpty(b, "%d", i)
pk, err := enc.Decrypt(b, tc.decode)
if tc.valid {
require.Nil(err, "%d: %+v", i, err)
assert.Equal(key, pk, "%d", i)
} else {
require.NotNil(err, "%d", i)
}
}
// now let's make sure raw bytes also work...
b := key.Bytes()
pk, err := enc.Decrypt(b, "")
require.Nil(err, "%+v", err)
assert.Equal(key, pk)
}

+ 19
- 8
keys/cryptostore/generator.go View File

@ -14,22 +14,22 @@ var (
// Generator determines the type of private key the keystore creates
type Generator interface {
Generate() crypto.PrivKey
Generate(secret []byte) crypto.PrivKey
}
// GenFunc is a helper to transform a function into a Generator
type GenFunc func() crypto.PrivKey
type GenFunc func(secret []byte) crypto.PrivKey
func (f GenFunc) Generate() crypto.PrivKey {
return f()
func (f GenFunc) Generate(secret []byte) crypto.PrivKey {
return f(secret)
}
func genEd25519() crypto.PrivKey {
return crypto.GenPrivKeyEd25519().Wrap()
func genEd25519(secret []byte) crypto.PrivKey {
return crypto.GenPrivKeyEd25519FromSecret(secret).Wrap()
}
func genSecp256() crypto.PrivKey {
return crypto.GenPrivKeySecp256k1().Wrap()
func genSecp256(secret []byte) crypto.PrivKey {
return crypto.GenPrivKeySecp256k1FromSecret(secret).Wrap()
}
func getGenerator(algo string) (Generator, error) {
@ -42,3 +42,14 @@ func getGenerator(algo string) (Generator, error) {
return nil, errors.Errorf("Cannot generate keys for algorithm: %s", algo)
}
}
func getGeneratorByType(typ byte) (Generator, error) {
switch typ {
case crypto.TypeEd25519:
return GenEd25519, nil
case crypto.TypeSecp256k1:
return GenSecp256k1, nil
default:
return nil, errors.Errorf("Cannot generate keys for algorithm: %X", typ)
}
}

+ 19
- 4
keys/cryptostore/holder.go View File

@ -43,12 +43,21 @@ func (s Manager) Create(name, passphrase, algo string) (keys.Info, string, error
if err != nil {
return keys.Info{}, "", err
}
key := gen.Generate()
// 128-bits are the all the randomness we can make use of
secret := crypto.CRandBytes(16)
key := gen.Generate(secret)
err = s.es.Put(name, passphrase, key)
if err != nil {
return keys.Info{}, "", err
}
seed, err := s.codec.BytesToWords(key.Bytes())
// we append the type byte to the serialized secret to help with recovery
// ie [secret] = [secret] + [type]
typ := key.Bytes()[0]
secret = append(secret, typ)
seed, err := s.codec.BytesToWords(secret)
phrase := strings.Join(seed, " ")
return info(name, key), phrase, err
}
@ -61,15 +70,21 @@ func (s Manager) Create(name, passphrase, algo string) (keys.Info, string, error
// Result similar to New(), except it doesn't return the seed again...
func (s Manager) Recover(name, passphrase, seedphrase string) (keys.Info, error) {
words := strings.Split(strings.TrimSpace(seedphrase), " ")
data, err := s.codec.WordsToBytes(words)
secret, err := s.codec.WordsToBytes(words)
if err != nil {
return keys.Info{}, err
}
key, err := crypto.PrivKeyFromBytes(data)
// secret is comprised of the actual secret with the type appended
// ie [secret] = [secret] + [type]
l := len(secret)
secret, typ := secret[:l-1], secret[l-1]
gen, err := getGeneratorByType(typ)
if err != nil {
return keys.Info{}, err
}
key := gen.Generate(secret)
// d00d, it worked! create the bugger....
err = s.es.Put(name, passphrase, key)


+ 29
- 10
keys/cryptostore/holder_test.go View File

@ -5,6 +5,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
cmn "github.com/tendermint/tmlibs/common"
crypto "github.com/tendermint/go-crypto"
"github.com/tendermint/go-crypto/keys"
"github.com/tendermint/go-crypto/keys/cryptostore"
@ -148,6 +151,32 @@ func assertPassword(assert *assert.Assertions, cstore cryptostore.Manager, name,
assert.Nil(err, "%+v", err)
}
// TestImportUnencrypted tests accepting raw priv keys bytes as input
func TestImportUnencrypted(t *testing.T) {
require := require.New(t)
// make the storage with reasonable defaults
cstore := cryptostore.New(
cryptostore.SecretBox,
memstorage.New(),
keys.MustLoadCodec("english"),
)
key := cryptostore.GenEd25519.Generate(cmn.RandBytes(16))
addr := key.PubKey().Address()
name := "john"
pass := "top-secret"
// import raw bytes
err := cstore.Import(name, pass, "", key.Bytes())
require.Nil(err, "%+v", err)
// make sure the address matches
info, err := cstore.Get(name)
require.Nil(err, "%+v", err)
require.EqualValues(addr, info.Address)
}
// TestAdvancedKeyManagement verifies update, import, export functionality
func TestAdvancedKeyManagement(t *testing.T) {
assert, require := assert.New(t), require.New(t)
@ -190,16 +219,6 @@ func TestAdvancedKeyManagement(t *testing.T) {
// import fails on bad transfer pass
err = cstore.Import(n2, p3, p2, exported)
assert.NotNil(err)
// import cannot overwrite existing keys
err = cstore.Import(n1, p3, pt, exported)
assert.NotNil(err)
// we can now import under another name
err = cstore.Import(n2, p3, pt, exported)
require.Nil(err, "%+v", err)
// make sure both passwords are now properly set (not to the transfer pass)
assertPassword(assert, cstore, n1, p2, pt)
assertPassword(assert, cstore, n2, p3, pt)
}
// TestSeedPhrase verifies restoring from a seed phrase


+ 5
- 1
keys/cryptostore/storage_test.go View File

@ -4,13 +4,17 @@ import (
"testing"
"github.com/stretchr/testify/assert"
crypto "github.com/tendermint/go-crypto"
cmn "github.com/tendermint/tmlibs/common"
keys "github.com/tendermint/go-crypto/keys"
)
func TestSortKeys(t *testing.T) {
assert := assert.New(t)
gen := GenEd25519.Generate
gen := func() crypto.PrivKey { return GenEd25519.Generate(cmn.RandBytes(16)) }
assert.NotEqual(gen(), gen())
// alphabetical order is n3, n1, n2


+ 73
- 6
keys/ecc.go View File

@ -5,6 +5,8 @@ import (
"errors"
"hash/crc32"
"hash/crc64"
"github.com/howeyc/crc16"
)
// ECC is used for anything that calculates an error-correcting code
@ -18,6 +20,9 @@ type ECC interface {
CheckECC([]byte) ([]byte, error)
}
var errInputTooShort = errors.New("input too short, no checksum present")
var errChecksumDoesntMatch = errors.New("checksum does not match")
// NoECC is a no-op placeholder, kind of useless... except for tests
type NoECC struct{}
@ -26,13 +31,75 @@ var _ ECC = NoECC{}
func (_ NoECC) AddECC(input []byte) []byte { return input }
func (_ NoECC) CheckECC(input []byte) ([]byte, error) { return input, nil }
// CRC16 does the ieee crc16 polynomial check
type CRC16 struct {
Poly uint16
table *crc16.Table
}
var _ ECC = (*CRC16)(nil)
const crc16ByteCount = 2
func NewIBMCRC16() *CRC16 {
return &CRC16{Poly: crc16.IBM}
}
func NewSCSICRC16() *CRC16 {
return &CRC16{Poly: crc16.SCSI}
}
func NewCCITTCRC16() *CRC16 {
return &CRC16{Poly: crc16.CCITT}
}
func (c *CRC16) AddECC(input []byte) []byte {
table := c.getTable()
// get crc and convert to some bytes...
crc := crc16.Checksum(input, table)
check := make([]byte, crc16ByteCount)
binary.BigEndian.PutUint16(check, crc)
// append it to the input
output := append(input, check...)
return output
}
func (c *CRC16) CheckECC(input []byte) ([]byte, error) {
table := c.getTable()
if len(input) <= crc16ByteCount {
return nil, errInputTooShort
}
cut := len(input) - crc16ByteCount
data, check := input[:cut], input[cut:]
crc := binary.BigEndian.Uint16(check)
calc := crc16.Checksum(data, table)
if crc != calc {
return nil, errChecksumDoesntMatch
}
return data, nil
}
func (c *CRC16) getTable() *crc16.Table {
if c.table != nil {
return c.table
}
if c.Poly == 0 {
c.Poly = crc16.IBM
}
c.table = crc16.MakeTable(c.Poly)
return c.table
}
// CRC32 does the ieee crc32 polynomial check
type CRC32 struct {
Poly uint32
table *crc32.Table
}
var _ ECC = &CRC32{}
var _ ECC = (*CRC32)(nil)
func NewIEEECRC32() *CRC32 {
return &CRC32{Poly: crc32.IEEE}
@ -63,14 +130,14 @@ func (c *CRC32) CheckECC(input []byte) ([]byte, error) {
table := c.getTable()
if len(input) <= crc32.Size {
return nil, errors.New("input too short, no checksum present")
return nil, errInputTooShort
}
cut := len(input) - crc32.Size
data, check := input[:cut], input[cut:]
crc := binary.BigEndian.Uint32(check)
calc := crc32.Checksum(data, table)
if crc != calc {
return nil, errors.New("Checksum does not match")
return nil, errChecksumDoesntMatch
}
return data, nil
}
@ -91,7 +158,7 @@ type CRC64 struct {
table *crc64.Table
}
var _ ECC = &CRC64{}
var _ ECC = (*CRC64)(nil)
func NewISOCRC64() *CRC64 {
return &CRC64{Poly: crc64.ISO}
@ -118,14 +185,14 @@ func (c *CRC64) CheckECC(input []byte) ([]byte, error) {
table := c.getTable()
if len(input) <= crc64.Size {
return nil, errors.New("input too short, no checksum present")
return nil, errInputTooShort
}
cut := len(input) - crc64.Size
data, check := input[:cut], input[cut:]
crc := binary.BigEndian.Uint64(check)
calc := crc64.Checksum(data, table)
if crc != calc {
return nil, errors.New("Checksum does not match")
return nil, errChecksumDoesntMatch
}
return data, nil
}


+ 13
- 16
keys/ecc_test.go View File

@ -8,18 +8,22 @@ import (
cmn "github.com/tendermint/tmlibs/common"
)
var codecs = []ECC{
NewIBMCRC16(),
NewSCSICRC16(),
NewCCITTCRC16(),
NewIEEECRC32(),
NewCastagnoliCRC32(),
NewKoopmanCRC32(),
NewISOCRC64(),
NewECMACRC64(),
}
// TestECCPasses makes sure that the AddECC/CheckECC methods are symetric
func TestECCPasses(t *testing.T) {
assert := assert.New(t)
checks := []ECC{
NoECC{},
NewIEEECRC32(),
NewCastagnoliCRC32(),
NewKoopmanCRC32(),
NewISOCRC64(),
NewECMACRC64(),
}
checks := append(codecs, NoECC{})
for _, check := range checks {
for i := 0; i < 2000; i++ {
@ -39,14 +43,7 @@ func TestECCPasses(t *testing.T) {
func TestECCFails(t *testing.T) {
assert := assert.New(t)
checks := []ECC{
NewIEEECRC32(),
NewCastagnoliCRC32(),
NewKoopmanCRC32(),
NewISOCRC64(),
NewECMACRC64(),
}
checks := codecs
attempts := 2000
for _, check := range checks {


+ 0
- 10
keys/tx/docs.go View File

@ -1,10 +0,0 @@
/*
package tx contains generic Signable implementations that can be used
by your application or tests to handle authentication needs.
It currently supports transaction data as opaque bytes and either single
or multiple private key signatures using straightforward algorithms.
It currently does not support N-of-M key share signing of other more
complex algorithms (although it would be great to add them)
*/
package tx

+ 0
- 67
keys/tx/multi.go View File

@ -1,67 +0,0 @@
package tx
import (
"github.com/pkg/errors"
crypto "github.com/tendermint/go-crypto"
data "github.com/tendermint/go-wire/data"
)
// MultiSig lets us wrap arbitrary data with a go-crypto signature
//
// TODO: rethink how we want to integrate this with KeyStore so it makes
// more sense (particularly the verify method)
type MultiSig struct {
Data data.Bytes
Sigs []Signed
}
type Signed struct {
Sig crypto.Signature
Pubkey crypto.PubKey
}
var _ SigInner = &MultiSig{}
func NewMulti(data []byte) Sig {
return Sig{&MultiSig{Data: data}}
}
// SignBytes returns the original data passed into `NewSig`
func (s *MultiSig) SignBytes() []byte {
return s.Data
}
// Sign will add a signature and pubkey.
//
// Depending on the Signable, one may be able to call this multiple times for multisig
// Returns error if called with invalid data or too many times
func (s *MultiSig) Sign(pubkey crypto.PubKey, sig crypto.Signature) error {
if pubkey.Empty() || sig.Empty() {
return errors.New("Signature or Key missing")
}
// set the value once we are happy
x := Signed{sig, pubkey}
s.Sigs = append(s.Sigs, x)
return nil
}
// Signers will return the public key(s) that signed if the signature
// is valid, or an error if there is any issue with the signature,
// including if there are no signatures
func (s *MultiSig) Signers() ([]crypto.PubKey, error) {
if len(s.Sigs) == 0 {
return nil, errors.New("Never signed")
}
keys := make([]crypto.PubKey, len(s.Sigs))
for i := range s.Sigs {
ms := s.Sigs[i]
if !ms.Pubkey.VerifyBytes(s.Data, ms.Sig) {
return nil, errors.Errorf("Signature %d doesn't match (key: %X)", i, ms.Pubkey.Bytes())
}
keys[i] = ms.Pubkey
}
return keys, nil
}

+ 0
- 78
keys/tx/multi_test.go View File

@ -1,78 +0,0 @@
package tx
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
crypto "github.com/tendermint/go-crypto"
keys "github.com/tendermint/go-crypto/keys"
"github.com/tendermint/go-crypto/keys/cryptostore"
"github.com/tendermint/go-crypto/keys/storage/memstorage"
)
func TestMultiSig(t *testing.T) {
assert, require := assert.New(t), require.New(t)
algo := crypto.NameEd25519
cstore := cryptostore.New(
cryptostore.SecretBox,
memstorage.New(),
keys.MustLoadCodec("english"),
)
n, p := "foo", "bar"
n2, p2 := "other", "thing"
acct, _, err := cstore.Create(n, p, algo)
require.Nil(err, "%+v", err)
acct2, _, err := cstore.Create(n2, p2, algo)
require.Nil(err, "%+v", err)
type signer struct {
key keys.Info
name, pass string
}
cases := []struct {
data string
signers []signer
}{
{"one", []signer{{acct, n, p}}},
{"two", []signer{{acct2, n2, p2}}},
{"both", []signer{{acct, n, p}, {acct2, n2, p2}}},
}
for _, tc := range cases {
tx := NewMulti([]byte(tc.data))
// unsigned version
_, err = tx.Signers()
assert.NotNil(err)
orig, err := tx.TxBytes()
require.Nil(err, "%+v", err)
data := tx.SignBytes()
assert.Equal(tc.data, string(data))
// sign it
for _, s := range tc.signers {
err = cstore.Sign(s.name, s.pass, tx)
require.Nil(err, "%+v", err)
}
// make sure it is proper now
sigs, err := tx.Signers()
require.Nil(err, "%+v", err)
if assert.Equal(len(tc.signers), len(sigs)) {
for i := range sigs {
// This must be refactored...
assert.Equal(tc.signers[i].key.PubKey, sigs[i])
}
}
// the tx bytes should change after this
after, err := tx.TxBytes()
require.Nil(err, "%+v", err)
assert.NotEqual(orig, after, "%X != %X", orig, after)
// sign bytes are the same
data = tx.SignBytes()
assert.Equal(tc.data, string(data))
}
}

+ 0
- 57
keys/tx/one.go View File

@ -1,57 +0,0 @@
package tx
import (
"github.com/pkg/errors"
crypto "github.com/tendermint/go-crypto"
data "github.com/tendermint/go-wire/data"
)
// OneSig lets us wrap arbitrary data with a go-crypto signature
//
// TODO: rethink how we want to integrate this with KeyStore so it makes
// more sense (particularly the verify method)
type OneSig struct {
Data data.Bytes
Signed
}
var _ SigInner = &OneSig{}
func New(data []byte) Sig {
return WrapSig(&OneSig{Data: data})
}
// SignBytes returns the original data passed into `NewSig`
func (s *OneSig) SignBytes() []byte {
return s.Data
}
// Sign will add a signature and pubkey.
//
// Depending on the Signable, one may be able to call this multiple times for multisig
// Returns error if called with invalid data or too many times
func (s *OneSig) Sign(pubkey crypto.PubKey, sig crypto.Signature) error {
if pubkey.Empty() || sig.Empty() {
return errors.New("Signature or Key missing")
}
if !s.Sig.Empty() {
return errors.New("Transaction can only be signed once")
}
// set the value once we are happy
s.Signed = Signed{sig, pubkey}
return nil
}
// Signers will return the public key(s) that signed if the signature
// is valid, or an error if there is any issue with the signature,
// including if there are no signatures
func (s *OneSig) Signers() ([]crypto.PubKey, error) {
if s.Pubkey.Empty() || s.Sig.Empty() {
return nil, errors.New("Never signed")
}
if !s.Pubkey.VerifyBytes(s.Data, s.Sig) {
return nil, errors.New("Signature doesn't match")
}
return []crypto.PubKey{s.Pubkey}, nil
}

+ 0
- 74
keys/tx/one_test.go View File

@ -1,74 +0,0 @@
package tx
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
crypto "github.com/tendermint/go-crypto"
keys "github.com/tendermint/go-crypto/keys"
"github.com/tendermint/go-crypto/keys/cryptostore"
"github.com/tendermint/go-crypto/keys/storage/memstorage"
)
func TestOneSig(t *testing.T) {
assert, require := assert.New(t), require.New(t)
algo := crypto.NameEd25519
cstore := cryptostore.New(
cryptostore.SecretBox,
memstorage.New(),
keys.MustLoadCodec("english"),
)
n, p := "foo", "bar"
n2, p2 := "other", "thing"
acct, _, err := cstore.Create(n, p, algo)
require.Nil(err, "%+v", err)
acct2, _, err := cstore.Create(n2, p2, algo)
require.Nil(err, "%+v", err)
cases := []struct {
data string
key keys.Info
name, pass string
}{
{"first", acct, n, p},
{"kehfkhefy8y", acct, n, p},
{"second", acct2, n2, p2},
}
for _, tc := range cases {
tx := New([]byte(tc.data))
// unsigned version
_, err = tx.Signers()
assert.NotNil(err)
orig, err := tx.TxBytes()
require.Nil(err, "%+v", err)
data := tx.SignBytes()
assert.Equal(tc.data, string(data))
// sign it
err = cstore.Sign(tc.name, tc.pass, tx)
require.Nil(err, "%+v", err)
// but not twice
err = cstore.Sign(tc.name, tc.pass, tx)
require.NotNil(err)
// make sure it is proper now
sigs, err := tx.Signers()
require.Nil(err, "%+v", err)
if assert.Equal(1, len(sigs)) {
// This must be refactored...
assert.Equal(tc.key.PubKey, sigs[0])
}
// the tx bytes should change after this
after, err := tx.TxBytes()
require.Nil(err, "%+v", err)
assert.NotEqual(orig, after, "%X != %X", orig, after)
// sign bytes are the same
data = tx.SignBytes()
assert.Equal(tc.data, string(data))
}
}

+ 0
- 76
keys/tx/reader.go View File

@ -1,76 +0,0 @@
package tx
import (
crypto "github.com/tendermint/go-crypto"
keys "github.com/tendermint/go-crypto/keys"
data "github.com/tendermint/go-wire/data"
)
const (
typeOneSig = byte(0x01)
typeMultiSig = byte(0x02)
nameOneSig = "sig"
nameMultiSig = "multi"
)
var _ keys.Signable = Sig{}
var TxMapper data.Mapper
func init() {
TxMapper = data.NewMapper(Sig{}).
RegisterImplementation(&OneSig{}, nameOneSig, typeOneSig).
RegisterImplementation(&MultiSig{}, nameMultiSig, typeMultiSig)
}
/*
DO NOT USE this interface.
It is public by necessity but should never be used directly
outside of this package.
Only use Sig, never SigInner
*/
type SigInner interface {
SignBytes() []byte
Sign(pubkey crypto.PubKey, sig crypto.Signature) error
Signers() ([]crypto.PubKey, error)
}
// Sig is what is exported, and handles serialization
type Sig struct {
SigInner
}
// TxBytes
func (s Sig) TxBytes() ([]byte, error) {
return data.ToWire(s)
}
// WrapSig goes from concrete implementation to "interface" struct
func WrapSig(pk SigInner) Sig {
if wrap, ok := pk.(Sig); ok {
pk = wrap.Unwrap()
}
return Sig{pk}
}
// Unwrap recovers the concrete interface safely (regardless of levels of embeds)
func (p Sig) Unwrap() SigInner {
pk := p.SigInner
for wrap, ok := pk.(Sig); ok; wrap, ok = pk.(Sig) {
pk = wrap.SigInner
}
return pk
}
func (p Sig) MarshalJSON() ([]byte, error) {
return TxMapper.ToJSON(p.Unwrap())
}
func (p *Sig) UnmarshalJSON(data []byte) (err error) {
parsed, err := TxMapper.FromJSON(data)
if err == nil && parsed != nil {
p.SigInner = parsed.(SigInner)
}
return
}

+ 0
- 72
keys/tx/reader_test.go View File

@ -1,72 +0,0 @@
package tx
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
crypto "github.com/tendermint/go-crypto"
"github.com/tendermint/go-crypto/keys"
"github.com/tendermint/go-crypto/keys/cryptostore"
"github.com/tendermint/go-crypto/keys/storage/memstorage"
data "github.com/tendermint/go-wire/data"
)
func TestReader(t *testing.T) {
assert, require := assert.New(t), require.New(t)
algo := crypto.NameEd25519
cstore := cryptostore.New(
cryptostore.SecretBox,
memstorage.New(),
keys.MustLoadCodec("english"),
)
type sigs struct{ name, pass string }
u := sigs{"alice", "1234"}
u2 := sigs{"bob", "foobar"}
_, _, err := cstore.Create(u.name, u.pass, algo)
require.Nil(err, "%+v", err)
_, _, err = cstore.Create(u2.name, u2.pass, algo)
require.Nil(err, "%+v", err)
cases := []struct {
tx Sig
sigs []sigs
}{
{New([]byte("first")), nil},
{New([]byte("second")), []sigs{u}},
{New([]byte("other")), []sigs{u2}},
{NewMulti([]byte("m-first")), nil},
{NewMulti([]byte("m-second")), []sigs{u}},
{NewMulti([]byte("m-other")), []sigs{u, u2}},
}
for _, tc := range cases {
tx := tc.tx
// make sure json serialization and loading works w/o sigs
var pre Sig
pjs, err := data.ToJSON(tx)
require.Nil(err, "%+v", err)
err = data.FromJSON(pjs, &pre)
require.Nil(err, "%+v", err)
assert.Equal(tx, pre)
for _, s := range tc.sigs {
err = cstore.Sign(s.name, s.pass, tx)
require.Nil(err, "%+v", err)
}
var post Sig
sjs, err := data.ToJSON(tx)
require.Nil(err, "%+v", err)
err = data.FromJSON(sjs, &post)
require.Nil(err, "%+v\n%s", err, string(sjs))
assert.Equal(tx, post)
if len(tc.sigs) > 0 {
assert.NotEqual(pjs, sjs, "%s\n ------ %s", string(pjs), string(sjs))
}
}
}

+ 1
- 0
keys/wordcodec.go View File

@ -35,6 +35,7 @@ func NewCodec(words []string) (codec *WordCodec, err error) {
words: words,
// TODO: configure this outside???
check: NewIEEECRC32(),
// check: NewIBMCRC16(),
}
return res, nil


+ 1
- 1
keys/wordcodec_test.go View File

@ -152,7 +152,7 @@ func TestCheckTypoDetection(t *testing.T) {
codec, err := LoadCodec(bank)
require.Nil(err, "%s: %+v", bank, err)
for i := 0; i < 1000; i++ {
numBytes := cmn.RandInt()%60 + 1
numBytes := cmn.RandInt()%60 + 4
data := cmn.RandBytes(numBytes)
words, err := codec.BytesToWords(data)


+ 0
- 1
signature.go View File

@ -23,7 +23,6 @@ type SignatureInner interface {
AssertIsSignatureInner()
Bytes() []byte
IsZero() bool
String() string
Equals(Signature) bool
Wrap() Signature
}


+ 0
- 111
tests/keys.sh View File

@ -1,111 +0,0 @@
#!/bin/bash
EXE=keys
oneTimeSetUp() {
PASS=qwertyuiop
export TM_HOME=$HOME/.keys_test
rm -rf $TM_HOME
assertTrue $?
}
newKey(){
assertNotNull "keyname required" "$1"
KEYPASS=${2:-qwertyuiop}
KEY=$(echo $KEYPASS | ${EXE} new $1 -o json)
if ! assertTrue "created $1" $?; then return 1; fi
assertEquals "$1" $(echo $KEY | jq .key.name | tr -d \")
return $?
}
# updateKey <name> <oldkey> <newkey>
updateKey() {
(echo $2; echo $3) | keys update $1 > /dev/null
return $?
}
test00MakeKeys() {
USER=demouser
assertFalse "already user $USER" "${EXE} get $USER"
newKey $USER
assertTrue "no user $USER" "${EXE} get $USER"
# make sure bad password not accepted
assertFalse "accepts short password" "echo 123 | keys new badpass"
}
test01ListKeys() {
# one line plus the number of keys
assertEquals "2" $(keys list | wc -l)
newKey foobar
assertEquals "3" $(keys list | wc -l)
# we got the proper name here...
assertEquals "foobar" $(keys list -o json | jq .[1].name | tr -d \" )
# we get all names in normal output
EXPECTEDNAMES=$(echo demouser; echo foobar)
TEXTNAMES=$(keys list | tail -n +2 | cut -f1)
assertEquals "$EXPECTEDNAMES" "$TEXTNAMES"
# let's make sure the addresses match!
assertEquals "text and json addresses don't match" $(keys list | tail -1 | cut -f3) $(keys list -o json | jq .[1].address | tr -d \")
}
test02updateKeys() {
USER=changer
PASS1=awsedrftgyhu
PASS2=S4H.9j.D9S7hso
PASS3=h8ybO7GY6d2
newKey $USER $PASS1
assertFalse "accepts invalid pass" "updateKey $USER $PASS2 $PASS2"
assertTrue "doesn't update" "updateKey $USER $PASS1 $PASS2"
assertTrue "takes new key after update" "updateKey $USER $PASS2 $PASS3"
}
test03recoverKeys() {
USER=sleepy
PASS1=S4H.9j.D9S7hso
USER2=easy
PASS2=1234567890
# make a user and check they exist
echo "create..."
KEY=$(echo $PASS1 | ${EXE} new $USER -o json)
if ! assertTrue "created $USER" $?; then return 1; fi
if [ -n "$DEBUG" ]; then echo $KEY; echo; fi
SEED=$(echo $KEY | jq .seed | tr -d \")
ADDR=$(echo $KEY | jq .key.address | tr -d \")
PUBKEY=$(echo $KEY | jq .key.pubkey | tr -d \")
assertTrue "${EXE} get $USER > /dev/null"
# let's delete this key
echo "delete..."
assertFalse "echo foo | ${EXE} delete $USER > /dev/null"
assertTrue "echo $PASS1 | ${EXE} delete $USER > /dev/null"
assertFalse "${EXE} get $USER > /dev/null"
# fails on short password
echo "recover..."
assertFalse "echo foo; echo $SEED | ${EXE} recover $USER2 -o json > /dev/null"
# fails on bad seed
assertFalse "echo $PASS2; echo \"silly white whale tower bongo\" | ${EXE} recover $USER2 -o json > /dev/null"
# now we got it
KEY2=$((echo $PASS2; echo $SEED) | ${EXE} recover $USER2 -o json)
if ! assertTrue "recovery failed: $KEY2" $?; then return 1; fi
if [ -n "$DEBUG" ]; then echo $KEY2; echo; fi
# make sure it looks the same
NAME2=$(echo $KEY2 | jq .name | tr -d \")
ADDR2=$(echo $KEY2 | jq .address | tr -d \")
PUBKEY2=$(echo $KEY2 | jq .pubkey | tr -d \")
assertEquals "wrong username" "$USER2" "$NAME2"
assertEquals "address doesn't match" "$ADDR" "$ADDR2"
assertEquals "pubkey doesn't match" "$PUBKEY" "$PUBKEY2"
# and we can find the info
assertTrue "${EXE} get $USER2 > /dev/null"
}
# load and run these tests with shunit2!
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory
. $DIR/shunit2

+ 1
- 1
version.go View File

@ -1,3 +1,3 @@
package crypto
const Version = "0.2.1"
const Version = "0.3.0"

Loading…
Cancel
Save