@ -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"` |
@ -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=" | |||
} | |||
} | |||
] | |||
``` |
@ -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 | |||
} |
@ -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 | |||
} |
@ -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() | |||
} |
@ -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 | |||
} |
@ -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)) | |||
} | |||
} |
@ -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 | |||
} |
@ -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) | |||
} |
@ -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 | |||
} |
@ -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 | |||
} |
@ -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)) | |||
} | |||
} |
@ -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 |
@ -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 | |||
} |
@ -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)) | |||
} | |||
} |
@ -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 | |||
} |
@ -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)) | |||
} | |||
} |
@ -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 | |||
} |
@ -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,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,3 +1,3 @@ | |||
package crypto | |||
const Version = "0.2.1" | |||
const Version = "0.3.0" |