@ -1,294 +0,0 @@ | |||||
package nano | |||||
import ( | |||||
"bytes" | |||||
"encoding/hex" | |||||
"github.com/pkg/errors" | |||||
ledger "github.com/ethanfrey/ledger" | |||||
crypto "github.com/tendermint/go-crypto" | |||||
amino "github.com/tendermint/go-amino" | |||||
) | |||||
//nolint | |||||
const ( | |||||
NameLedgerEd25519 = "ledger-ed25519" | |||||
TypeLedgerEd25519 = 0x10 | |||||
// Timeout is the number of seconds to wait for a response from the ledger | |||||
// if eg. waiting for user confirmation on button push | |||||
Timeout = 20 | |||||
) | |||||
var device *ledger.Ledger | |||||
// getLedger gets a copy of the device, and caches it | |||||
func getLedger() (*ledger.Ledger, error) { | |||||
var err error | |||||
if device == nil { | |||||
device, err = ledger.FindLedger() | |||||
} | |||||
return device, err | |||||
} | |||||
func signLedger(device *ledger.Ledger, msg []byte) (pub crypto.PubKey, sig crypto.Signature, err error) { | |||||
var resp []byte | |||||
packets := generateSignRequests(msg) | |||||
for _, pack := range packets { | |||||
resp, err = device.Exchange(pack, Timeout) | |||||
if err != nil { | |||||
return pub, sig, err | |||||
} | |||||
} | |||||
// the last call is the result we want and needs to be parsed | |||||
key, bsig, err := parseDigest(resp) | |||||
if err != nil { | |||||
return pub, sig, err | |||||
} | |||||
var b [32]byte | |||||
copy(b[:], key) | |||||
return PubKeyLedgerEd25519FromBytes(b), crypto.SignatureEd25519FromBytes(bsig), nil | |||||
} | |||||
// PrivKeyLedgerEd25519 implements PrivKey, calling the ledger nano | |||||
// we cache the PubKey from the first call to use it later | |||||
type PrivKeyLedgerEd25519 struct { | |||||
// PubKey should be private, but we want to encode it via go-amino | |||||
// so we can view the address later, even without having the ledger | |||||
// attached | |||||
CachedPubKey crypto.PubKey | |||||
} | |||||
// NewPrivKeyLedgerEd25519 will generate a new key and store the | |||||
// public key for later use. | |||||
func NewPrivKeyLedgerEd25519() (crypto.PrivKey, error) { | |||||
var pk PrivKeyLedgerEd25519 | |||||
// getPubKey will cache the pubkey for later use, | |||||
// this allows us to return an error early if the ledger | |||||
// is not plugged in | |||||
_, err := pk.getPubKey() | |||||
return pk.Wrap(), err | |||||
} | |||||
// ValidateKey allows us to verify the sanity of a key | |||||
// after loading it from disk | |||||
func (pk *PrivKeyLedgerEd25519) ValidateKey() error { | |||||
// getPubKey will return an error if the ledger is not | |||||
// properly set up... | |||||
pub, err := pk.forceGetPubKey() | |||||
if err != nil { | |||||
return err | |||||
} | |||||
// verify this matches cached address | |||||
if !pub.Equals(pk.CachedPubKey) { | |||||
return errors.New("ledger doesn't match cached key") | |||||
} | |||||
return nil | |||||
} | |||||
// AssertIsPrivKeyInner fulfils PrivKey Interface | |||||
func (pk *PrivKeyLedgerEd25519) AssertIsPrivKeyInner() {} | |||||
// Bytes fulfils PrivKey Interface - but it stores the cached pubkey so we can verify | |||||
// the same key when we reconnect to a ledger | |||||
func (pk *PrivKeyLedgerEd25519) Bytes() []byte { | |||||
return amino.BinaryBytes(pk.Wrap()) | |||||
} | |||||
// Sign calls the ledger and stores the PubKey for future use | |||||
// | |||||
// XXX/TODO: panics if there is an error communicating with the ledger. | |||||
// | |||||
// Communication is checked on NewPrivKeyLedger and PrivKeyFromBytes, | |||||
// returning an error, so this should only trigger if the privkey is held | |||||
// in memory for a while before use. | |||||
func (pk *PrivKeyLedgerEd25519) Sign(msg []byte) crypto.Signature { | |||||
// oh, I wish there was better error handling | |||||
dev, err := getLedger() | |||||
if err != nil { | |||||
panic(err) | |||||
} | |||||
pub, sig, err := signLedger(dev, msg) | |||||
if err != nil { | |||||
panic(err) | |||||
} | |||||
// if we have no pubkey yet, store it for future queries | |||||
if pk.CachedPubKey.Empty() { | |||||
pk.CachedPubKey = pub | |||||
} else if !pk.CachedPubKey.Equals(pub) { | |||||
panic("signed with a different key than stored") | |||||
} | |||||
return sig | |||||
} | |||||
// PubKey returns the stored PubKey | |||||
// TODO: query the ledger if not there, once it is not volatile | |||||
func (pk *PrivKeyLedgerEd25519) PubKey() crypto.PubKey { | |||||
key, err := pk.getPubKey() | |||||
if err != nil { | |||||
panic(err) | |||||
} | |||||
return key | |||||
} | |||||
// getPubKey reads the pubkey from cache or from the ledger itself | |||||
// since this involves IO, it may return an error, which is not exposed | |||||
// in the PubKey interface, so this function allows better error handling | |||||
func (pk *PrivKeyLedgerEd25519) getPubKey() (key crypto.PubKey, err error) { | |||||
// if we have no pubkey, set it | |||||
if pk.CachedPubKey.Empty() { | |||||
pk.CachedPubKey, err = pk.forceGetPubKey() | |||||
} | |||||
return pk.CachedPubKey, err | |||||
} | |||||
// forceGetPubKey is like getPubKey but ignores any cached key | |||||
// and ensures we get it from the ledger itself. | |||||
func (pk *PrivKeyLedgerEd25519) forceGetPubKey() (key crypto.PubKey, err error) { | |||||
dev, err := getLedger() | |||||
if err != nil { | |||||
return key, errors.New("Can't connect to ledger device") | |||||
} | |||||
key, _, err = signLedger(dev, []byte{0}) | |||||
if err != nil { | |||||
return key, errors.New("Please open cosmos app on the ledger") | |||||
} | |||||
return key, err | |||||
} | |||||
// Equals fulfils PrivKey Interface - makes sure both keys refer to the | |||||
// same | |||||
func (pk *PrivKeyLedgerEd25519) Equals(other crypto.PrivKey) bool { | |||||
if ledger, ok := other.Unwrap().(*PrivKeyLedgerEd25519); ok { | |||||
return pk.CachedPubKey.Equals(ledger.CachedPubKey) | |||||
} | |||||
return false | |||||
} | |||||
// MockPrivKeyLedgerEd25519 behaves as the ledger, but stores a pre-packaged call-response | |||||
// for use in test cases | |||||
type MockPrivKeyLedgerEd25519 struct { | |||||
Msg []byte | |||||
Pub [KeyLength]byte | |||||
Sig [SigLength]byte | |||||
} | |||||
// NewMockKey returns | |||||
func NewMockKey(msg, pubkey, sig string) (pk MockPrivKeyLedgerEd25519) { | |||||
var err error | |||||
pk.Msg, err = hex.DecodeString(msg) | |||||
if err != nil { | |||||
panic(err) | |||||
} | |||||
bpk, err := hex.DecodeString(pubkey) | |||||
if err != nil { | |||||
panic(err) | |||||
} | |||||
bsig, err := hex.DecodeString(sig) | |||||
if err != nil { | |||||
panic(err) | |||||
} | |||||
copy(pk.Pub[:], bpk) | |||||
copy(pk.Sig[:], bsig) | |||||
return pk | |||||
} | |||||
var _ crypto.PrivKeyInner = MockPrivKeyLedgerEd25519{} | |||||
// AssertIsPrivKeyInner fulfils PrivKey Interface | |||||
func (pk MockPrivKeyLedgerEd25519) AssertIsPrivKeyInner() {} | |||||
// Bytes fulfils PrivKey Interface - not supported | |||||
func (pk MockPrivKeyLedgerEd25519) Bytes() []byte { | |||||
return nil | |||||
} | |||||
// Sign returns a real SignatureLedger, if the msg matches what we expect | |||||
func (pk MockPrivKeyLedgerEd25519) Sign(msg []byte) crypto.Signature { | |||||
if !bytes.Equal(pk.Msg, msg) { | |||||
panic("Mock key is for different msg") | |||||
} | |||||
return crypto.SignatureEd25519(pk.Sig).Wrap() | |||||
} | |||||
// PubKey returns a real PubKeyLedgerEd25519, that will verify this signature | |||||
func (pk MockPrivKeyLedgerEd25519) PubKey() crypto.PubKey { | |||||
return PubKeyLedgerEd25519FromBytes(pk.Pub) | |||||
} | |||||
// Equals compares that two Mocks have the same data | |||||
func (pk MockPrivKeyLedgerEd25519) Equals(other crypto.PrivKey) bool { | |||||
if mock, ok := other.Unwrap().(MockPrivKeyLedgerEd25519); ok { | |||||
return bytes.Equal(mock.Pub[:], pk.Pub[:]) && | |||||
bytes.Equal(mock.Sig[:], pk.Sig[:]) && | |||||
bytes.Equal(mock.Msg, pk.Msg) | |||||
} | |||||
return false | |||||
} | |||||
//////////////////////////////////////////// | |||||
// pubkey | |||||
// PubKeyLedgerEd25519 works like a normal Ed25519 except a hash before the verify bytes | |||||
type PubKeyLedgerEd25519 struct { | |||||
crypto.PubKeyEd25519 | |||||
} | |||||
// PubKeyLedgerEd25519FromBytes creates a PubKey from the raw bytes | |||||
func PubKeyLedgerEd25519FromBytes(key [32]byte) crypto.PubKey { | |||||
return PubKeyLedgerEd25519{crypto.PubKeyEd25519(key)}.Wrap() | |||||
} | |||||
// Bytes fulfils pk Interface - no data, just type info | |||||
func (pk PubKeyLedgerEd25519) Bytes() []byte { | |||||
return amino.BinaryBytes(pk.Wrap()) | |||||
} | |||||
// VerifyBytes uses the normal Ed25519 algorithm but a sha512 hash beforehand | |||||
func (pk PubKeyLedgerEd25519) VerifyBytes(msg []byte, sig crypto.Signature) bool { | |||||
hmsg := hashMsg(msg) | |||||
return pk.PubKeyEd25519.VerifyBytes(hmsg, sig) | |||||
} | |||||
// Equals implements PubKey interface | |||||
func (pk PubKeyLedgerEd25519) Equals(other crypto.PubKey) bool { | |||||
if ledger, ok := other.Unwrap().(PubKeyLedgerEd25519); ok { | |||||
return pk.PubKeyEd25519.Equals(ledger.PubKeyEd25519.Wrap()) | |||||
} | |||||
return false | |||||
} | |||||
/*** registration with go-data ***/ | |||||
func init() { | |||||
crypto.PrivKeyMapper. | |||||
RegisterImplementation(&PrivKeyLedgerEd25519{}, NameLedgerEd25519, TypeLedgerEd25519). | |||||
RegisterImplementation(MockPrivKeyLedgerEd25519{}, "mock-ledger", 0x11) | |||||
crypto.PubKeyMapper. | |||||
RegisterImplementation(PubKeyLedgerEd25519{}, NameLedgerEd25519, TypeLedgerEd25519) | |||||
} | |||||
// Wrap fulfils interface for PrivKey struct | |||||
func (pk *PrivKeyLedgerEd25519) Wrap() crypto.PrivKey { | |||||
return crypto.PrivKey{PrivKeyInner: pk} | |||||
} | |||||
// Wrap fulfils interface for PrivKey struct | |||||
func (pk MockPrivKeyLedgerEd25519) Wrap() crypto.PrivKey { | |||||
return crypto.PrivKey{PrivKeyInner: pk} | |||||
} | |||||
// Wrap fulfils interface for PubKey struct | |||||
func (pk PubKeyLedgerEd25519) Wrap() crypto.PubKey { | |||||
return crypto.PubKey{PubKeyInner: pk} | |||||
} |
@ -1,142 +0,0 @@ | |||||
package nano | |||||
import ( | |||||
"encoding/hex" | |||||
"os" | |||||
"testing" | |||||
asrt "github.com/stretchr/testify/assert" | |||||
rqr "github.com/stretchr/testify/require" | |||||
crypto "github.com/tendermint/go-crypto" | |||||
) | |||||
func TestLedgerKeys(t *testing.T) { | |||||
assert, require := asrt.New(t), rqr.New(t) | |||||
cases := []struct { | |||||
msg, pubkey, sig string | |||||
valid bool | |||||
}{ | |||||
0: { | |||||
msg: "F00D", | |||||
pubkey: "8E8754F012C2FDB492183D41437FD837CB81D8BBE731924E2E0DAF43FD3F2C93", | |||||
sig: "787DC03E9E4EE05983E30BAE0DEFB8DB0671DBC2F5874AC93F8D8CA4018F7A42D6F9A9BCEADB422AC8E27CEE9CA205A0B88D22CD686F0A43EB806E8190A3C400", | |||||
valid: true, | |||||
}, | |||||
1: { | |||||
msg: "DEADBEEF", | |||||
pubkey: "0C45ADC887A5463F668533443C829ED13EA8E2E890C778957DC28DB9D2AD5A6C", | |||||
sig: "00ED74EED8FDAC7988A14BF6BC222120CBAC249D569AF4C2ADABFC86B792F97DF73C4919BE4B6B0ACB53547273BF29FBF0A9E0992FFAB6CB6C9B09311FC86A00", | |||||
valid: true, | |||||
}, | |||||
2: { | |||||
msg: "1234567890AA", | |||||
pubkey: "598FC1F0C76363D14D7480736DEEF390D85863360F075792A6975EFA149FD7EA", | |||||
sig: "59AAB7D7BDC4F936B6415DE672A8B77FA6B8B3451CD95B3A631F31F9A05DAEEE5E7E4F89B64DDEBB5F63DC042CA13B8FCB8185F82AD7FD5636FFDA6B0DC9570B", | |||||
valid: true, | |||||
}, | |||||
3: { | |||||
msg: "1234432112344321", | |||||
pubkey: "359E0636E780457294CCA5D2D84DB190C3EDBD6879729C10D3963DEA1D5D8120", | |||||
sig: "616B44EC7A65E7C719C170D669A47DE80C6AC0BB13FBCC89230976F9CC14D4CF9ECF26D4AFBB9FFF625599F1FF6F78EDA15E9F6B6BDCE07CFE9D8C407AC45208", | |||||
valid: true, | |||||
}, | |||||
4: { | |||||
msg: "12344321123443", | |||||
pubkey: "359E0636E780457294CCA5D2D84DB190C3EDBD6879729C10D3963DEA1D5D8120", | |||||
sig: "616B44EC7A65E7C719C170D669A47DE80C6AC0BB13FBCC89230976F9CC14D4CF9ECF26D4AFBB9FFF625599F1FF6F78EDA15E9F6B6BDCE07CFE9D8C407AC45208", | |||||
valid: false, | |||||
}, | |||||
5: { | |||||
msg: "1234432112344321", | |||||
pubkey: "459E0636E780457294CCA5D2D84DB190C3EDBD6879729C10D3963DEA1D5D8120", | |||||
sig: "616B44EC7A65E7C719C170D669A47DE80C6AC0BB13FBCC89230976F9CC14D4CF9ECF26D4AFBB9FFF625599F1FF6F78EDA15E9F6B6BDCE07CFE9D8C407AC45208", | |||||
valid: false, | |||||
}, | |||||
6: { | |||||
msg: "1234432112344321", | |||||
pubkey: "359E0636E780457294CCA5D2D84DB190C3EDBD6879729C10D3963DEA1D5D8120", | |||||
sig: "716B44EC7A65E7C719C170D669A47DE80C6AC0BB13FBCC89230976F9CC14D4CF9ECF26D4AFBB9FFF625599F1FF6F78EDA15E9F6B6BDCE07CFE9D8C407AC45208", | |||||
valid: false, | |||||
}, | |||||
} | |||||
for i, tc := range cases { | |||||
bmsg, err := hex.DecodeString(tc.msg) | |||||
require.NoError(err, "%d", i) | |||||
priv := NewMockKey(tc.msg, tc.pubkey, tc.sig) | |||||
pub := priv.PubKey() | |||||
sig := priv.Sign(bmsg) | |||||
valid := pub.VerifyBytes(bmsg, sig) | |||||
assert.Equal(tc.valid, valid, "%d", i) | |||||
} | |||||
} | |||||
func TestRealLedger(t *testing.T) { | |||||
assert, require := asrt.New(t), rqr.New(t) | |||||
if os.Getenv("WITH_LEDGER") == "" { | |||||
t.Skip("Set WITH_LEDGER to run code on real ledger") | |||||
} | |||||
msg := []byte("kuhehfeohg") | |||||
priv, err := NewPrivKeyLedgerEd25519() | |||||
require.Nil(err, "%+v", err) | |||||
pub := priv.PubKey() | |||||
sig := priv.Sign(msg) | |||||
valid := pub.VerifyBytes(msg, sig) | |||||
assert.True(valid) | |||||
// now, let's serialize the key and make sure it still works | |||||
bs := priv.Bytes() | |||||
priv2, err := crypto.PrivKeyFromBytes(bs) | |||||
require.Nil(err, "%+v", err) | |||||
// make sure we get the same pubkey when we load from disk | |||||
pub2 := priv2.PubKey() | |||||
require.Equal(pub, pub2) | |||||
// signing with the loaded key should match the original pubkey | |||||
sig = priv2.Sign(msg) | |||||
valid = pub.VerifyBytes(msg, sig) | |||||
assert.True(valid) | |||||
// make sure pubkeys serialize properly as well | |||||
bs = pub.Bytes() | |||||
bpub, err := crypto.PubKeyFromBytes(bs) | |||||
require.NoError(err) | |||||
assert.Equal(pub, bpub) | |||||
} | |||||
// TestRealLedgerErrorHandling calls. These tests assume | |||||
// the ledger is not plugged in.... | |||||
func TestRealLedgerErrorHandling(t *testing.T) { | |||||
require := rqr.New(t) | |||||
if os.Getenv("WITH_LEDGER") != "" { | |||||
t.Skip("Skipping on WITH_LEDGER as it tests unplugged cases") | |||||
} | |||||
// first, try to generate a key, must return an error | |||||
// (no panic) | |||||
_, err := NewPrivKeyLedgerEd25519() | |||||
require.Error(err) | |||||
led := PrivKeyLedgerEd25519{} // empty | |||||
// or with some pub key | |||||
ed := crypto.GenPrivKeyEd25519() | |||||
led2 := PrivKeyLedgerEd25519{CachedPubKey: ed.PubKey()} | |||||
// loading these should return errors | |||||
bs := led.Bytes() | |||||
_, err = crypto.PrivKeyFromBytes(bs) | |||||
require.Error(err) | |||||
bs = led2.Bytes() | |||||
_, err = crypto.PrivKeyFromBytes(bs) | |||||
require.Error(err) | |||||
} |
@ -1,63 +0,0 @@ | |||||
package nano | |||||
import ( | |||||
"bytes" | |||||
"crypto/sha512" | |||||
"github.com/pkg/errors" | |||||
) | |||||
const ( | |||||
App = 0x80 | |||||
Init = 0x00 | |||||
Update = 0x01 | |||||
Digest = 0x02 | |||||
MaxChunk = 253 | |||||
KeyLength = 32 | |||||
SigLength = 64 | |||||
) | |||||
var separator = []byte{0, 0xCA, 0xFE, 0} | |||||
func generateSignRequests(payload []byte) [][]byte { | |||||
// nice one-shot | |||||
digest := []byte{App, Digest} | |||||
if len(payload) < MaxChunk { | |||||
return [][]byte{append(digest, payload...)} | |||||
} | |||||
// large payload is multi-chunk | |||||
result := [][]byte{{App, Init}} | |||||
update := []byte{App, Update} | |||||
for len(payload) > MaxChunk { | |||||
msg := append(update, payload[:MaxChunk]...) | |||||
payload = payload[MaxChunk:] | |||||
result = append(result, msg) | |||||
} | |||||
result = append(result, append(update, payload...)) | |||||
result = append(result, digest) | |||||
return result | |||||
} | |||||
func parseDigest(resp []byte) (key, sig []byte, err error) { | |||||
if resp[0] != App || resp[1] != Digest { | |||||
return nil, nil, errors.New("Invalid header") | |||||
} | |||||
resp = resp[2:] | |||||
if len(resp) != KeyLength+SigLength+len(separator) { | |||||
return nil, nil, errors.Errorf("Incorrect length: %d", len(resp)) | |||||
} | |||||
key, resp = resp[:KeyLength], resp[KeyLength:] | |||||
if !bytes.Equal(separator, resp[:len(separator)]) { | |||||
return nil, nil, errors.New("Cannot find 0xCAFE") | |||||
} | |||||
sig = resp[len(separator):] | |||||
return key, sig, nil | |||||
} | |||||
func hashMsg(data []byte) []byte { | |||||
res := sha512.Sum512(data) | |||||
return res[:] | |||||
} |
@ -1,160 +0,0 @@ | |||||
package nano | |||||
import ( | |||||
"encoding/hex" | |||||
"testing" | |||||
"github.com/pkg/errors" | |||||
asrt "github.com/stretchr/testify/assert" | |||||
rqr "github.com/stretchr/testify/require" | |||||
crypto "github.com/tendermint/go-crypto" | |||||
) | |||||
func parseEdKey(data []byte) (key crypto.PubKey, err error) { | |||||
ed := crypto.PubKeyEd25519{} | |||||
if len(data) < len(ed) { | |||||
return key, errors.Errorf("Key length too short: %d", len(data)) | |||||
} | |||||
copy(ed[:], data) | |||||
return ed.Wrap(), nil | |||||
} | |||||
func parseSig(data []byte) (key crypto.Signature, err error) { | |||||
ed := crypto.SignatureEd25519{} | |||||
if len(data) < len(ed) { | |||||
return key, errors.Errorf("Sig length too short: %d", len(data)) | |||||
} | |||||
copy(ed[:], data) | |||||
return ed.Wrap(), nil | |||||
} | |||||
func TestParseDigest(t *testing.T) { | |||||
assert, require := asrt.New(t), rqr.New(t) | |||||
cases := []struct { | |||||
output string | |||||
key string | |||||
sig string | |||||
valid bool | |||||
}{ | |||||
{ | |||||
output: "80028E8754F012C2FDB492183D41437FD837CB81D8BBE731924E2E0DAF43FD3F2C9300CAFE00787DC03E9E4EE05983E30BAE0DEFB8DB0671DBC2F5874AC93F8D8CA4018F7A42D6F9A9BCEADB422AC8E27CEE9CA205A0B88D22CD686F0A43EB806E8190A3C400", | |||||
key: "8E8754F012C2FDB492183D41437FD837CB81D8BBE731924E2E0DAF43FD3F2C93", | |||||
sig: "787DC03E9E4EE05983E30BAE0DEFB8DB0671DBC2F5874AC93F8D8CA4018F7A42D6F9A9BCEADB422AC8E27CEE9CA205A0B88D22CD686F0A43EB806E8190A3C400", | |||||
valid: true, | |||||
}, | |||||
{ | |||||
output: "800235467890876543525437890796574535467890", | |||||
key: "", | |||||
sig: "", | |||||
valid: false, | |||||
}, | |||||
} | |||||
for i, tc := range cases { | |||||
msg, err := hex.DecodeString(tc.output) | |||||
require.Nil(err, "%d: %+v", i, err) | |||||
lKey, lSig, err := parseDigest(msg) | |||||
if !tc.valid { | |||||
assert.NotNil(err, "%d", i) | |||||
} else if assert.Nil(err, "%d: %+v", i, err) { | |||||
key, err := hex.DecodeString(tc.key) | |||||
require.Nil(err, "%d: %+v", i, err) | |||||
sig, err := hex.DecodeString(tc.sig) | |||||
require.Nil(err, "%d: %+v", i, err) | |||||
assert.Equal(key, lKey, "%d", i) | |||||
assert.Equal(sig, lSig, "%d", i) | |||||
} | |||||
} | |||||
} | |||||
type cryptoCase struct { | |||||
msg string | |||||
key string | |||||
sig string | |||||
valid bool | |||||
} | |||||
func toBytes(c cryptoCase) (msg, key, sig []byte, err error) { | |||||
msg, err = hex.DecodeString(c.msg) | |||||
if err != nil { | |||||
return | |||||
} | |||||
key, err = hex.DecodeString(c.key) | |||||
if err != nil { | |||||
return | |||||
} | |||||
sig, err = hex.DecodeString(c.sig) | |||||
return | |||||
} | |||||
func TestCryptoConvert(t *testing.T) { | |||||
assert, require := asrt.New(t), rqr.New(t) | |||||
cases := []cryptoCase{ | |||||
0: { | |||||
msg: "F00D", | |||||
key: "8E8754F012C2FDB492183D41437FD837CB81D8BBE731924E2E0DAF43FD3F2C93", | |||||
sig: "787DC03E9E4EE05983E30BAE0DEFB8DB0671DBC2F5874AC93F8D8CA4018F7A42D6F9A9BCEADB422AC8E27CEE9CA205A0B88D22CD686F0A43EB806E8190A3C400", | |||||
valid: true, | |||||
}, | |||||
1: { | |||||
msg: "DEADBEEF", | |||||
key: "0C45ADC887A5463F668533443C829ED13EA8E2E890C778957DC28DB9D2AD5A6C", | |||||
sig: "00ED74EED8FDAC7988A14BF6BC222120CBAC249D569AF4C2ADABFC86B792F97DF73C4919BE4B6B0ACB53547273BF29FBF0A9E0992FFAB6CB6C9B09311FC86A00", | |||||
valid: true, | |||||
}, | |||||
2: { | |||||
msg: "1234567890AA", | |||||
key: "598FC1F0C76363D14D7480736DEEF390D85863360F075792A6975EFA149FD7EA", | |||||
sig: "59AAB7D7BDC4F936B6415DE672A8B77FA6B8B3451CD95B3A631F31F9A05DAEEE5E7E4F89B64DDEBB5F63DC042CA13B8FCB8185F82AD7FD5636FFDA6B0DC9570B", | |||||
valid: true, | |||||
}, | |||||
3: { | |||||
msg: "1234432112344321", | |||||
key: "359E0636E780457294CCA5D2D84DB190C3EDBD6879729C10D3963DEA1D5D8120", | |||||
sig: "616B44EC7A65E7C719C170D669A47DE80C6AC0BB13FBCC89230976F9CC14D4CF9ECF26D4AFBB9FFF625599F1FF6F78EDA15E9F6B6BDCE07CFE9D8C407AC45208", | |||||
valid: true, | |||||
}, | |||||
4: { | |||||
msg: "12344321123443", | |||||
key: "359E0636E780457294CCA5D2D84DB190C3EDBD6879729C10D3963DEA1D5D8120", | |||||
sig: "616B44EC7A65E7C719C170D669A47DE80C6AC0BB13FBCC89230976F9CC14D4CF9ECF26D4AFBB9FFF625599F1FF6F78EDA15E9F6B6BDCE07CFE9D8C407AC45208", | |||||
valid: false, | |||||
}, | |||||
5: { | |||||
msg: "1234432112344321", | |||||
key: "459E0636E780457294CCA5D2D84DB190C3EDBD6879729C10D3963DEA1D5D8120", | |||||
sig: "616B44EC7A65E7C719C170D669A47DE80C6AC0BB13FBCC89230976F9CC14D4CF9ECF26D4AFBB9FFF625599F1FF6F78EDA15E9F6B6BDCE07CFE9D8C407AC45208", | |||||
valid: false, | |||||
}, | |||||
6: { | |||||
msg: "1234432112344321", | |||||
key: "359E0636E780457294CCA5D2D84DB190C3EDBD6879729C10D3963DEA1D5D8120", | |||||
sig: "716B44EC7A65E7C719C170D669A47DE80C6AC0BB13FBCC89230976F9CC14D4CF9ECF26D4AFBB9FFF625599F1FF6F78EDA15E9F6B6BDCE07CFE9D8C407AC45208", | |||||
valid: false, | |||||
}, | |||||
} | |||||
for i, tc := range cases { | |||||
msg, key, sig, err := toBytes(tc) | |||||
require.Nil(err, "%d: %+v", i, err) | |||||
pk, err := parseEdKey(key) | |||||
require.Nil(err, "%d: %+v", i, err) | |||||
psig, err := parseSig(sig) | |||||
require.Nil(err, "%d: %+v", i, err) | |||||
// it is not the signature of the message itself | |||||
valid := pk.VerifyBytes(msg, psig) | |||||
assert.False(valid, "%d", i) | |||||
// but rather of the hash of the msg | |||||
hmsg := hashMsg(msg) | |||||
valid = pk.VerifyBytes(hmsg, psig) | |||||
assert.Equal(tc.valid, valid, "%d", i) | |||||
} | |||||
} |