// createFilter creates a message filter to check against installed handlers. func createFilter(message *Message, topics []Topic) filter.Filter { matcher := make([][]Topic, len(topics)) for i, topic := range topics { matcher[i] = []Topic{topic} } return filterer{ to: string(crypto.FromECDSAPub(message.To)), from: string(crypto.FromECDSAPub(message.Recover())), matcher: newTopicMatcher(matcher...), } }
// Watch installs a new message handler to run in case a matching packet arrives // from the whisper network. func (self *Whisper) Watch(options Filter) int { filter := filterer{ to: string(crypto.FromECDSAPub(options.To)), from: string(crypto.FromECDSAPub(options.From)), matcher: newTopicMatcher(options.Topics...), fn: func(data interface{}) { options.Fn(data.(*Message)) }, } return self.filters.Install(filter) }
// NewWhisperMessage converts an internal message into an API version. func NewWhisperMessage(message *whisper.Message) WhisperMessage { return WhisperMessage{ ref: message, Payload: common.ToHex(message.Payload), From: common.ToHex(crypto.FromECDSAPub(message.Recover())), To: common.ToHex(crypto.FromECDSAPub(message.To)), Sent: message.Sent.Unix(), TTL: int64(message.TTL / time.Second), Hash: common.ToHex(message.Hash.Bytes()), } }
func TestSigning(t *testing.T) { seckey, err := crypto.HexToECDSA("2934473d31f55a8a7c031bdef35b9587b40249969211aca5c29925cb04f84ccc") checkErr(t, err) t.Logf("Private key length: %v", len(crypto.FromECDSA(seckey))) t.Logf("private key: %x", crypto.FromECDSA(seckey)) t.Logf("public key: %x", crypto.FromECDSAPub(&seckey.PublicKey)) hdr, clm := jwsCompactParams(t) // Signed compact representation sm, err := Sign(seckey, hdr, clm, "foo") checkErr(t, err) _, err = sm.EncodeCompactJWS() // smc checkErr(t, err) r1, err := Base64Decode(sm.Signature) checkErr(t, err) t.Logf("Signature length == %v", len(r1)) if len(r1) != 65 { t.Fatal("Invalid signature length") } res, err := sm.Verify(&seckey.PublicKey, "foo") checkErr(t, err) if err != nil || res == false { t.Fatal("Failed to recover a public key from signature") } }
// makeAuthMsg creates the initiator handshake message. func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey, token []byte) (*authMsgV4, error) { rpub, err := h.remoteID.Pubkey() if err != nil { return nil, fmt.Errorf("bad remoteID: %v", err) } h.remotePub = ecies.ImportECDSAPublic(rpub) // Generate random initiator nonce. h.initNonce = make([]byte, shaLen) if _, err := rand.Read(h.initNonce); err != nil { return nil, err } // Generate random keypair to for ECDH. h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil) if err != nil { return nil, err } // Sign known message: static-shared-secret ^ nonce token, err = h.staticSharedSecret(prv) if err != nil { return nil, err } signed := xor(token, h.initNonce) signature, err := crypto.Sign(signed, h.randomPrivKey.ExportECDSA()) if err != nil { return nil, err } msg := new(authMsgV4) copy(msg.Signature[:], signature) copy(msg.InitiatorPubkey[:], crypto.FromECDSAPub(&prv.PublicKey)[1:]) copy(msg.Nonce[:], h.initNonce) msg.Version = 4 return msg, nil }
// NewIdentity generates a new cryptographic identity for the client, and injects // it into the known identities for message decryption. func (s *PublicWhisperAPI) NewIdentity() (string, error) { if s.w == nil { return "", whisperOffLineErr } identity := s.w.NewIdentity() return common.ToHex(crypto.FromECDSAPub(&identity.PublicKey)), nil }
func ToQMessage(msg *whisper.Message) *Message { return &Message{ ref: msg, Flags: int32(msg.Flags), Payload: "0x" + common.Bytes2Hex(msg.Payload), From: "0x" + common.Bytes2Hex(crypto.FromECDSAPub(msg.Recover())), } }
// NewIdentity generates a new cryptographic identity for the client, and injects // it into the known identities for message decryption. func (self *Whisper) NewIdentity() *ecdsa.PrivateKey { key, err := crypto.GenerateKey() if err != nil { panic(err) } self.keys[string(crypto.FromECDSAPub(&key.PublicKey))] = key return key }
func (tx *Transaction) PublicKey() []byte { hash := tx.Hash() v, r, s := tx.Curve() sig := append(r, s...) sig = append(sig, v-27) //pubkey := crypto.Ecrecover(append(hash[:], sig...)) //pubkey, _ := secp256k1.RecoverPubkey(hash[:], sig) p, err := crypto.SigToPub(hash[:], sig) if err != nil { glog.V(logger.Error).Infof("Could not get pubkey from signature: ", err) return nil } pubkey := crypto.FromECDSAPub(p) return pubkey }
func (tx *Transaction) PublicKey() ([]byte, error) { if !crypto.ValidateSignatureValues(tx.V, tx.R, tx.S) { return nil, errors.New("invalid v, r, s values") } hash := tx.Hash() v, r, s := tx.GetSignatureValues() sig := append(r, s...) sig = append(sig, v-27) p, err := crypto.SigToPub(hash[:], sig) if err != nil { glog.V(logger.Error).Infof("Could not get pubkey from signature: ", err) return nil, err } pubkey := crypto.FromECDSAPub(p) if len(pubkey) == 0 || pubkey[0] != 4 { return nil, errors.New("invalid public key") } return pubkey, nil }
// authMsg creates an encrypted initiator handshake message. func (h *encHandshake) authMsg(prv *ecdsa.PrivateKey, token []byte) ([]byte, error) { var tokenFlag byte if token == nil { // no session token found means we need to generate shared secret. // ecies shared secret is used as initial session token for new peers // generate shared key from prv and remote pubkey var err error if token, err = h.ecdhShared(prv); err != nil { return nil, err } } else { // for known peers, we use stored token from the previous session tokenFlag = 0x01 } // sign known message: // ecdh-shared-secret^nonce for new peers // token^nonce for old peers signed := xor(token, h.initNonce) signature, err := crypto.Sign(signed, h.randomPrivKey.ExportECDSA()) if err != nil { return nil, err } // encode auth message // signature || sha3(ecdhe-random-pubk) || pubk || nonce || token-flag msg := make([]byte, authMsgLen) n := copy(msg, signature) n += copy(msg[n:], crypto.Sha3(exportPubkey(&h.randomPrivKey.PublicKey))) n += copy(msg[n:], crypto.FromECDSAPub(&prv.PublicKey)[1:]) n += copy(msg[n:], h.initNonce) msg[n] = tokenFlag // encrypt auth message using remote-pubk return ecies.Encrypt(rand.Reader, h.remotePub, msg, nil, nil) }
func TestHandshakeForwardCompatibility(t *testing.T) { var ( keyA, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") keyB, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") pubA = crypto.FromECDSAPub(&keyA.PublicKey)[1:] pubB = crypto.FromECDSAPub(&keyB.PublicKey)[1:] ephA, _ = crypto.HexToECDSA("869d6ecf5211f1cc60418a13b9d870b22959d0c16f02bec714c960dd2298a32d") ephB, _ = crypto.HexToECDSA("e238eb8e04fee6511ab04c6dd3c89ce097b11f25d584863ac2b6d5b35b1847e4") ephPubA = crypto.FromECDSAPub(&ephA.PublicKey)[1:] ephPubB = crypto.FromECDSAPub(&ephB.PublicKey)[1:] nonceA = unhex("7e968bba13b6c50e2c4cd7f241cc0d64d1ac25c7f5952df231ac6a2bda8ee5d6") nonceB = unhex("559aead08264d5795d3909718cdd05abd49572e84fe55590eef31a88a08fdffd") _, _, _, _ = pubA, pubB, ephPubA, ephPubB authSignature = unhex("299ca6acfd35e3d72d8ba3d1e2b60b5561d5af5218eb5bc182045769eb4226910a301acae3b369fffc4a4899d6b02531e89fd4fe36a2cf0d93607ba470b50f7800") _ = authSignature ) makeAuth := func(test handshakeAuthTest) *authMsgV4 { msg := &authMsgV4{Version: test.wantVersion, Rest: test.wantRest, gotPlain: test.isPlain} copy(msg.Signature[:], authSignature) copy(msg.InitiatorPubkey[:], pubA) copy(msg.Nonce[:], nonceA) return msg } makeAck := func(test handshakeAckTest) *authRespV4 { msg := &authRespV4{Version: test.wantVersion, Rest: test.wantRest} copy(msg.RandomPubkey[:], ephPubB) copy(msg.Nonce[:], nonceB) return msg } // check auth msg parsing for _, test := range eip8HandshakeAuthTests { r := bytes.NewReader(unhex(test.input)) msg := new(authMsgV4) ciphertext, err := readHandshakeMsg(msg, encAuthMsgLen, keyB, r) if err != nil { t.Errorf("error for input %x:\n %v", unhex(test.input), err) continue } if !bytes.Equal(ciphertext, unhex(test.input)) { t.Errorf("wrong ciphertext for input %x:\n %x", unhex(test.input), ciphertext) } want := makeAuth(test) if !reflect.DeepEqual(msg, want) { t.Errorf("wrong msg for input %x:\ngot %s\nwant %s", unhex(test.input), spew.Sdump(msg), spew.Sdump(want)) } } // check auth resp parsing for _, test := range eip8HandshakeRespTests { input := unhex(test.input) r := bytes.NewReader(input) msg := new(authRespV4) ciphertext, err := readHandshakeMsg(msg, encAuthRespLen, keyA, r) if err != nil { t.Errorf("error for input %x:\n %v", input, err) continue } if !bytes.Equal(ciphertext, input) { t.Errorf("wrong ciphertext for input %x:\n %x", input, err) } want := makeAck(test) if !reflect.DeepEqual(msg, want) { t.Errorf("wrong msg for input %x:\ngot %s\nwant %s", input, spew.Sdump(msg), spew.Sdump(want)) } } // check derivation for (Auth₂, Ack₂) on recipient side var ( hs = &encHandshake{ initiator: false, respNonce: nonceB, randomPrivKey: ecies.ImportECDSA(ephB), } authCiphertext = unhex(eip8HandshakeAuthTests[1].input) authRespCiphertext = unhex(eip8HandshakeRespTests[1].input) authMsg = makeAuth(eip8HandshakeAuthTests[1]) wantAES = unhex("80e8632c05fed6fc2a13b0f8d31a3cf645366239170ea067065aba8e28bac487") wantMAC = unhex("2ea74ec5dae199227dff1af715362700e989d889d7a493cb0639691efb8e5f98") wantFooIngressHash = unhex("0c7ec6340062cc46f5e9f1e3cf86f8c8c403c5a0964f5df0ebd34a75ddc86db5") ) if err := hs.handleAuthMsg(authMsg, keyB); err != nil { t.Fatalf("handleAuthMsg: %v", err) } derived, err := hs.secrets(authCiphertext, authRespCiphertext) if err != nil { t.Fatalf("secrets: %v", err) } if !bytes.Equal(derived.AES, wantAES) { t.Errorf("aes-secret mismatch:\ngot %x\nwant %x", derived.AES, wantAES) } if !bytes.Equal(derived.MAC, wantMAC) { t.Errorf("mac-secret mismatch:\ngot %x\nwant %x", derived.MAC, wantMAC) } io.WriteString(derived.IngressMAC, "foo") fooIngressHash := derived.IngressMAC.Sum(nil) if !bytes.Equal(fooIngressHash, wantFooIngressHash) { t.Errorf("ingress-mac('foo') mismatch:\ngot %x\nwant %x", fooIngressHash, wantFooIngressHash) } }
// GetIdentity retrieves the private key of the specified public identity. func (self *Whisper) GetIdentity(key *ecdsa.PublicKey) *ecdsa.PrivateKey { return self.keys[string(crypto.FromECDSAPub(key))] }
// HasIdentity checks if the the whisper node is configured with the private key // of the specified public pair. func (self *Whisper) HasIdentity(key *ecdsa.PublicKey) bool { return self.keys[string(crypto.FromECDSAPub(key))] != nil }
// NewIdentity generates a new cryptographic identity for the client, and injects // it into the known identities for message decryption. func (self *Whisper) NewIdentity() string { identity := self.Whisper.NewIdentity() return common.ToHex(crypto.FromECDSAPub(&identity.PublicKey)) }