mirror of
https://github.com/fluencelabs/tendermint
synced 2025-05-17 00:51:20 +00:00
Merge pull request #23 from tendermint/feature/short-recover-text
Shorter recovery seed
This commit is contained in:
commit
bf355d1b58
24
glide.lock
generated
24
glide.lock
generated
@ -1,5 +1,5 @@
|
|||||||
hash: 3bcee9fbccf29d21217b24b6a83ec51e1514f37b2ae5d8718cf6c5df80f4fb2c
|
hash: c0a2db1b80c6b1b8aab31c526ce43e22e49b23c893c78b8fdb8546aa2e7b7cc6
|
||||||
updated: 2017-06-19T17:16:58.037568333+02:00
|
updated: 2017-07-22T05:24:42.82932575-04:00
|
||||||
imports:
|
imports:
|
||||||
- name: github.com/bgentry/speakeasy
|
- name: github.com/bgentry/speakeasy
|
||||||
version: 4aabc24848ce5fd31929f7d1e4ea74d3709c14cd
|
version: 4aabc24848ce5fd31929f7d1e4ea74d3709c14cd
|
||||||
@ -38,11 +38,11 @@ imports:
|
|||||||
- name: github.com/gorilla/context
|
- name: github.com/gorilla/context
|
||||||
version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42
|
version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42
|
||||||
- name: github.com/gorilla/handlers
|
- name: github.com/gorilla/handlers
|
||||||
version: 3a5767ca75ece5f7f1440b1d16975247f8d8b221
|
version: a4043c62cc2329bacda331d33fc908ab11ef0ec3
|
||||||
- name: github.com/gorilla/mux
|
- name: github.com/gorilla/mux
|
||||||
version: 392c28fe23e1c45ddba891b0320b3b5df220beea
|
version: bcd8bc72b08df0f70df986b97f95590779502d31
|
||||||
- name: github.com/hashicorp/hcl
|
- name: github.com/hashicorp/hcl
|
||||||
version: a4b07c25de5ff55ad3b8936cea69a79a3d95a855
|
version: 392dba7d905ed5d04a5794ba89f558b27e2ba1ca
|
||||||
subpackages:
|
subpackages:
|
||||||
- hcl/ast
|
- hcl/ast
|
||||||
- hcl/parser
|
- hcl/parser
|
||||||
@ -52,6 +52,8 @@ imports:
|
|||||||
- json/parser
|
- json/parser
|
||||||
- json/scanner
|
- json/scanner
|
||||||
- json/token
|
- json/token
|
||||||
|
- name: github.com/howeyc/crc16
|
||||||
|
version: 58da63c846043d0bea709c8d47039df06577d6d9
|
||||||
- name: github.com/inconshreveable/mousetrap
|
- name: github.com/inconshreveable/mousetrap
|
||||||
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
||||||
- name: github.com/kr/logfmt
|
- name: github.com/kr/logfmt
|
||||||
@ -67,7 +69,7 @@ imports:
|
|||||||
- name: github.com/pelletier/go-toml
|
- name: github.com/pelletier/go-toml
|
||||||
version: 13d49d4606eb801b8f01ae542b4afc4c6ee3d84a
|
version: 13d49d4606eb801b8f01ae542b4afc4c6ee3d84a
|
||||||
- name: github.com/pkg/errors
|
- name: github.com/pkg/errors
|
||||||
version: ff09b135c25aae272398c51a07235b90a75aa4f0
|
version: 645ef00459ed84a119197bfb8d8205042c6df63d
|
||||||
- name: github.com/spf13/afero
|
- name: github.com/spf13/afero
|
||||||
version: 9be650865eab0c12963d8753212f4f9c66cdcf12
|
version: 9be650865eab0c12963d8753212f4f9c66cdcf12
|
||||||
subpackages:
|
subpackages:
|
||||||
@ -75,11 +77,11 @@ imports:
|
|||||||
- name: github.com/spf13/cast
|
- name: github.com/spf13/cast
|
||||||
version: acbeb36b902d72a7a4c18e8f3241075e7ab763e4
|
version: acbeb36b902d72a7a4c18e8f3241075e7ab763e4
|
||||||
- name: github.com/spf13/cobra
|
- name: github.com/spf13/cobra
|
||||||
version: db6b9a8b3f3f400c8ecb4a4d7d02245b8facad66
|
version: 4cdb38c072b86bf795d2c81de50784d9fdd6eb77
|
||||||
- name: github.com/spf13/jwalterweatherman
|
- name: github.com/spf13/jwalterweatherman
|
||||||
version: fa7ca7e836cf3a8bb4ebf799f472c12d7e903d66
|
version: 8f07c835e5cc1450c082fe3a439cf87b0cbb2d99
|
||||||
- name: github.com/spf13/pflag
|
- name: github.com/spf13/pflag
|
||||||
version: 80fe0fb4eba54167e2ccae1c6c950e72abf61b73
|
version: e57e3eeb33f795204c1ca35f56c44f83227c6e66
|
||||||
- name: github.com/spf13/viper
|
- name: github.com/spf13/viper
|
||||||
version: 0967fc9aceab2ce9da34061253ac10fb99bba5b2
|
version: 0967fc9aceab2ce9da34061253ac10fb99bba5b2
|
||||||
- name: github.com/tendermint/ed25519
|
- name: github.com/tendermint/ed25519
|
||||||
@ -93,7 +95,7 @@ imports:
|
|||||||
- data
|
- data
|
||||||
- data/base58
|
- data/base58
|
||||||
- name: github.com/tendermint/tmlibs
|
- name: github.com/tendermint/tmlibs
|
||||||
version: bd9d0d1637dadf1330e167189d5e5031aadcda6f
|
version: 2f6f3e6aa70bb19b70a6e73210273fa127041070
|
||||||
subpackages:
|
subpackages:
|
||||||
- cli
|
- cli
|
||||||
- common
|
- common
|
||||||
@ -111,7 +113,7 @@ imports:
|
|||||||
- ripemd160
|
- ripemd160
|
||||||
- salsa20/salsa
|
- salsa20/salsa
|
||||||
- name: golang.org/x/sys
|
- name: golang.org/x/sys
|
||||||
version: 9ccfe848b9db8435a24c424abbc07a921adf1df5
|
version: e62c3de784db939836898e5c19ffd41bece347da
|
||||||
subpackages:
|
subpackages:
|
||||||
- unix
|
- unix
|
||||||
- name: golang.org/x/text
|
- name: golang.org/x/text
|
||||||
|
@ -29,6 +29,7 @@ import:
|
|||||||
- package: github.com/spf13/cobra
|
- package: github.com/spf13/cobra
|
||||||
- package: github.com/spf13/viper
|
- package: github.com/spf13/viper
|
||||||
- package: gopkg.in/go-playground/validator.v9
|
- package: gopkg.in/go-playground/validator.v9
|
||||||
|
- package: github.com/howeyc/crc16
|
||||||
testImport:
|
testImport:
|
||||||
- package: github.com/mndrix/btcutil
|
- package: github.com/mndrix/btcutil
|
||||||
- package: github.com/stretchr/testify
|
- package: github.com/stretchr/testify
|
||||||
|
@ -5,6 +5,9 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
|
|
||||||
"github.com/tendermint/go-crypto/keys/cryptostore"
|
"github.com/tendermint/go-crypto/keys/cryptostore"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -12,8 +15,8 @@ func TestNoopEncoder(t *testing.T) {
|
|||||||
assert, require := assert.New(t), require.New(t)
|
assert, require := assert.New(t), require.New(t)
|
||||||
noop := cryptostore.Noop
|
noop := cryptostore.Noop
|
||||||
|
|
||||||
key := cryptostore.GenEd25519.Generate()
|
key := cryptostore.GenEd25519.Generate(cmn.RandBytes(16))
|
||||||
key2 := cryptostore.GenSecp256k1.Generate()
|
key2 := cryptostore.GenSecp256k1.Generate(cmn.RandBytes(16))
|
||||||
|
|
||||||
b, err := noop.Encrypt(key, "encode")
|
b, err := noop.Encrypt(key, "encode")
|
||||||
require.Nil(err)
|
require.Nil(err)
|
||||||
@ -40,7 +43,7 @@ func TestSecretBox(t *testing.T) {
|
|||||||
assert, require := assert.New(t), require.New(t)
|
assert, require := assert.New(t), require.New(t)
|
||||||
enc := cryptostore.SecretBox
|
enc := cryptostore.SecretBox
|
||||||
|
|
||||||
key := cryptostore.GenEd25519.Generate()
|
key := cryptostore.GenEd25519.Generate(cmn.RandBytes(16))
|
||||||
pass := "some-special-secret"
|
pass := "some-special-secret"
|
||||||
|
|
||||||
b, err := enc.Encrypt(key, pass)
|
b, err := enc.Encrypt(key, pass)
|
||||||
|
@ -14,22 +14,22 @@ var (
|
|||||||
|
|
||||||
// Generator determines the type of private key the keystore creates
|
// Generator determines the type of private key the keystore creates
|
||||||
type Generator interface {
|
type Generator interface {
|
||||||
Generate() crypto.PrivKey
|
Generate(secret []byte) crypto.PrivKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenFunc is a helper to transform a function into a Generator
|
// 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 {
|
func (f GenFunc) Generate(secret []byte) crypto.PrivKey {
|
||||||
return f()
|
return f(secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func genEd25519() crypto.PrivKey {
|
func genEd25519(secret []byte) crypto.PrivKey {
|
||||||
return crypto.GenPrivKeyEd25519().Wrap()
|
return crypto.GenPrivKeyEd25519FromSecret(secret).Wrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
func genSecp256() crypto.PrivKey {
|
func genSecp256(secret []byte) crypto.PrivKey {
|
||||||
return crypto.GenPrivKeySecp256k1().Wrap()
|
return crypto.GenPrivKeySecp256k1FromSecret(secret).Wrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getGenerator(algo string) (Generator, error) {
|
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)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -43,12 +43,21 @@ func (s Manager) Create(name, passphrase, algo string) (keys.Info, string, error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return keys.Info{}, "", err
|
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)
|
err = s.es.Put(name, passphrase, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return keys.Info{}, "", err
|
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, " ")
|
phrase := strings.Join(seed, " ")
|
||||||
return info(name, key), phrase, err
|
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...
|
// Result similar to New(), except it doesn't return the seed again...
|
||||||
func (s Manager) Recover(name, passphrase, seedphrase string) (keys.Info, error) {
|
func (s Manager) Recover(name, passphrase, seedphrase string) (keys.Info, error) {
|
||||||
words := strings.Split(strings.TrimSpace(seedphrase), " ")
|
words := strings.Split(strings.TrimSpace(seedphrase), " ")
|
||||||
data, err := s.codec.WordsToBytes(words)
|
secret, err := s.codec.WordsToBytes(words)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return keys.Info{}, err
|
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 {
|
if err != nil {
|
||||||
return keys.Info{}, err
|
return keys.Info{}, err
|
||||||
}
|
}
|
||||||
|
key := gen.Generate(secret)
|
||||||
|
|
||||||
// d00d, it worked! create the bugger....
|
// d00d, it worked! create the bugger....
|
||||||
err = s.es.Put(name, passphrase, key)
|
err = s.es.Put(name, passphrase, key)
|
||||||
|
@ -4,13 +4,17 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
|
|
||||||
keys "github.com/tendermint/go-crypto/keys"
|
keys "github.com/tendermint/go-crypto/keys"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSortKeys(t *testing.T) {
|
func TestSortKeys(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
gen := GenEd25519.Generate
|
gen := func() crypto.PrivKey { return GenEd25519.Generate(cmn.RandBytes(16)) }
|
||||||
assert.NotEqual(gen(), gen())
|
assert.NotEqual(gen(), gen())
|
||||||
|
|
||||||
// alphabetical order is n3, n1, n2
|
// alphabetical order is n3, n1, n2
|
||||||
|
79
keys/ecc.go
79
keys/ecc.go
@ -5,6 +5,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"hash/crc64"
|
"hash/crc64"
|
||||||
|
|
||||||
|
"github.com/howeyc/crc16"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ECC is used for anything that calculates an error-correcting code
|
// ECC is used for anything that calculates an error-correcting code
|
||||||
@ -18,6 +20,9 @@ type ECC interface {
|
|||||||
CheckECC([]byte) ([]byte, error)
|
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
|
// NoECC is a no-op placeholder, kind of useless... except for tests
|
||||||
type NoECC struct{}
|
type NoECC struct{}
|
||||||
|
|
||||||
@ -26,13 +31,75 @@ var _ ECC = NoECC{}
|
|||||||
func (_ NoECC) AddECC(input []byte) []byte { return input }
|
func (_ NoECC) AddECC(input []byte) []byte { return input }
|
||||||
func (_ NoECC) CheckECC(input []byte) ([]byte, error) { return input, nil }
|
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
|
// CRC32 does the ieee crc32 polynomial check
|
||||||
type CRC32 struct {
|
type CRC32 struct {
|
||||||
Poly uint32
|
Poly uint32
|
||||||
table *crc32.Table
|
table *crc32.Table
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ ECC = &CRC32{}
|
var _ ECC = (*CRC32)(nil)
|
||||||
|
|
||||||
func NewIEEECRC32() *CRC32 {
|
func NewIEEECRC32() *CRC32 {
|
||||||
return &CRC32{Poly: crc32.IEEE}
|
return &CRC32{Poly: crc32.IEEE}
|
||||||
@ -63,14 +130,14 @@ func (c *CRC32) CheckECC(input []byte) ([]byte, error) {
|
|||||||
table := c.getTable()
|
table := c.getTable()
|
||||||
|
|
||||||
if len(input) <= crc32.Size {
|
if len(input) <= crc32.Size {
|
||||||
return nil, errors.New("input too short, no checksum present")
|
return nil, errInputTooShort
|
||||||
}
|
}
|
||||||
cut := len(input) - crc32.Size
|
cut := len(input) - crc32.Size
|
||||||
data, check := input[:cut], input[cut:]
|
data, check := input[:cut], input[cut:]
|
||||||
crc := binary.BigEndian.Uint32(check)
|
crc := binary.BigEndian.Uint32(check)
|
||||||
calc := crc32.Checksum(data, table)
|
calc := crc32.Checksum(data, table)
|
||||||
if crc != calc {
|
if crc != calc {
|
||||||
return nil, errors.New("Checksum does not match")
|
return nil, errChecksumDoesntMatch
|
||||||
}
|
}
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
@ -91,7 +158,7 @@ type CRC64 struct {
|
|||||||
table *crc64.Table
|
table *crc64.Table
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ ECC = &CRC64{}
|
var _ ECC = (*CRC64)(nil)
|
||||||
|
|
||||||
func NewISOCRC64() *CRC64 {
|
func NewISOCRC64() *CRC64 {
|
||||||
return &CRC64{Poly: crc64.ISO}
|
return &CRC64{Poly: crc64.ISO}
|
||||||
@ -118,14 +185,14 @@ func (c *CRC64) CheckECC(input []byte) ([]byte, error) {
|
|||||||
table := c.getTable()
|
table := c.getTable()
|
||||||
|
|
||||||
if len(input) <= crc64.Size {
|
if len(input) <= crc64.Size {
|
||||||
return nil, errors.New("input too short, no checksum present")
|
return nil, errInputTooShort
|
||||||
}
|
}
|
||||||
cut := len(input) - crc64.Size
|
cut := len(input) - crc64.Size
|
||||||
data, check := input[:cut], input[cut:]
|
data, check := input[:cut], input[cut:]
|
||||||
crc := binary.BigEndian.Uint64(check)
|
crc := binary.BigEndian.Uint64(check)
|
||||||
calc := crc64.Checksum(data, table)
|
calc := crc64.Checksum(data, table)
|
||||||
if crc != calc {
|
if crc != calc {
|
||||||
return nil, errors.New("Checksum does not match")
|
return nil, errChecksumDoesntMatch
|
||||||
}
|
}
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,10 @@ import (
|
|||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestECCPasses makes sure that the AddECC/CheckECC methods are symetric
|
var codecs = []ECC{
|
||||||
func TestECCPasses(t *testing.T) {
|
NewIBMCRC16(),
|
||||||
assert := assert.New(t)
|
NewSCSICRC16(),
|
||||||
|
NewCCITTCRC16(),
|
||||||
checks := []ECC{
|
|
||||||
NoECC{},
|
|
||||||
NewIEEECRC32(),
|
NewIEEECRC32(),
|
||||||
NewCastagnoliCRC32(),
|
NewCastagnoliCRC32(),
|
||||||
NewKoopmanCRC32(),
|
NewKoopmanCRC32(),
|
||||||
@ -21,6 +19,12 @@ func TestECCPasses(t *testing.T) {
|
|||||||
NewECMACRC64(),
|
NewECMACRC64(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestECCPasses makes sure that the AddECC/CheckECC methods are symetric
|
||||||
|
func TestECCPasses(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
checks := append(codecs, NoECC{})
|
||||||
|
|
||||||
for _, check := range checks {
|
for _, check := range checks {
|
||||||
for i := 0; i < 2000; i++ {
|
for i := 0; i < 2000; i++ {
|
||||||
numBytes := cmn.RandInt()%60 + 1
|
numBytes := cmn.RandInt()%60 + 1
|
||||||
@ -39,14 +43,7 @@ func TestECCPasses(t *testing.T) {
|
|||||||
func TestECCFails(t *testing.T) {
|
func TestECCFails(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
checks := []ECC{
|
checks := codecs
|
||||||
NewIEEECRC32(),
|
|
||||||
NewCastagnoliCRC32(),
|
|
||||||
NewKoopmanCRC32(),
|
|
||||||
NewISOCRC64(),
|
|
||||||
NewECMACRC64(),
|
|
||||||
}
|
|
||||||
|
|
||||||
attempts := 2000
|
attempts := 2000
|
||||||
|
|
||||||
for _, check := range checks {
|
for _, check := range checks {
|
||||||
|
@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -34,7 +34,8 @@ func NewCodec(words []string) (codec *WordCodec, err error) {
|
|||||||
res := &WordCodec{
|
res := &WordCodec{
|
||||||
words: words,
|
words: words,
|
||||||
// TODO: configure this outside???
|
// TODO: configure this outside???
|
||||||
check: NewIEEECRC32(),
|
// check: NewIEEECRC32(),
|
||||||
|
check: NewIBMCRC16(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
|
@ -152,7 +152,7 @@ func TestCheckTypoDetection(t *testing.T) {
|
|||||||
codec, err := LoadCodec(bank)
|
codec, err := LoadCodec(bank)
|
||||||
require.Nil(err, "%s: %+v", bank, err)
|
require.Nil(err, "%s: %+v", bank, err)
|
||||||
for i := 0; i < 1000; i++ {
|
for i := 0; i < 1000; i++ {
|
||||||
numBytes := cmn.RandInt()%60 + 1
|
numBytes := cmn.RandInt()%60 + 4
|
||||||
data := cmn.RandBytes(numBytes)
|
data := cmn.RandBytes(numBytes)
|
||||||
|
|
||||||
words, err := codec.BytesToWords(data)
|
words, err := codec.BytesToWords(data)
|
||||||
|
@ -68,7 +68,6 @@ test03recoverKeys() {
|
|||||||
PASS2=1234567890
|
PASS2=1234567890
|
||||||
|
|
||||||
# make a user and check they exist
|
# make a user and check they exist
|
||||||
echo "create..."
|
|
||||||
KEY=$(echo $PASS1 | ${EXE} new $USER -o json)
|
KEY=$(echo $PASS1 | ${EXE} new $USER -o json)
|
||||||
if ! assertTrue "created $USER" $?; then return 1; fi
|
if ! assertTrue "created $USER" $?; then return 1; fi
|
||||||
if [ -n "$DEBUG" ]; then echo $KEY; echo; fi
|
if [ -n "$DEBUG" ]; then echo $KEY; echo; fi
|
||||||
@ -79,13 +78,11 @@ test03recoverKeys() {
|
|||||||
assertTrue "${EXE} get $USER > /dev/null"
|
assertTrue "${EXE} get $USER > /dev/null"
|
||||||
|
|
||||||
# let's delete this key
|
# let's delete this key
|
||||||
echo "delete..."
|
|
||||||
assertFalse "echo foo | ${EXE} delete $USER > /dev/null"
|
assertFalse "echo foo | ${EXE} delete $USER > /dev/null"
|
||||||
assertTrue "echo $PASS1 | ${EXE} delete $USER > /dev/null"
|
assertTrue "echo $PASS1 | ${EXE} delete $USER > /dev/null"
|
||||||
assertFalse "${EXE} get $USER > /dev/null"
|
assertFalse "${EXE} get $USER > /dev/null"
|
||||||
|
|
||||||
# fails on short password
|
# fails on short password
|
||||||
echo "recover..."
|
|
||||||
assertFalse "echo foo; echo $SEED | ${EXE} recover $USER2 -o json > /dev/null"
|
assertFalse "echo foo; echo $SEED | ${EXE} recover $USER2 -o json > /dev/null"
|
||||||
# fails on bad seed
|
# fails on bad seed
|
||||||
assertFalse "echo $PASS2; echo \"silly white whale tower bongo\" | ${EXE} recover $USER2 -o json > /dev/null"
|
assertFalse "echo $PASS2; echo \"silly white whale tower bongo\" | ${EXE} recover $USER2 -o json > /dev/null"
|
||||||
@ -106,6 +103,40 @@ test03recoverKeys() {
|
|||||||
assertTrue "${EXE} get $USER2 > /dev/null"
|
assertTrue "${EXE} get $USER2 > /dev/null"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# try recovery with secp256k1 keys
|
||||||
|
test03recoverSecp() {
|
||||||
|
USER=dings
|
||||||
|
PASS1=Sbub-U9byS7hso
|
||||||
|
|
||||||
|
USER2=booms
|
||||||
|
PASS2=1234567890
|
||||||
|
|
||||||
|
KEY=$(echo $PASS1 | ${EXE} new $USER -o json -t secp256k1)
|
||||||
|
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"
|
||||||
|
|
||||||
|
# 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!
|
# load and run these tests with shunit2!
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory
|
||||||
. $DIR/shunit2
|
. $DIR/shunit2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user