209 lines
6.5 KiB
Diff
209 lines
6.5 KiB
Diff
diff --git i/whisper/whisperv6/api.go w/whisper/whisperv6/api.go
|
|
index c60bc46a1..2de99f293 100644
|
|
--- i/whisper/whisperv6/api.go
|
|
+++ w/whisper/whisperv6/api.go
|
|
@@ -317,6 +317,16 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (hexutil.
|
|
return result, err
|
|
}
|
|
|
|
+// UninstallFilter is alias for Unsubscribe
|
|
+func (api *PublicWhisperAPI) UninstallFilter(id string) {
|
|
+ api.w.Unsubscribe(id)
|
|
+}
|
|
+
|
|
+// Unsubscribe disables and removes an existing filter.
|
|
+func (api *PublicWhisperAPI) Unsubscribe(id string) {
|
|
+ api.w.Unsubscribe(id)
|
|
+}
|
|
+
|
|
//go:generate gencodec -type Criteria -field-override criteriaOverride -out gen_criteria_json.go
|
|
|
|
// Criteria holds various filter options for inbound messages.
|
|
diff --git i/whisper/whisperv6/whisper.go w/whisper/whisperv6/whisper.go
|
|
index 880cced09..702556079 100644
|
|
--- i/whisper/whisperv6/whisper.go
|
|
+++ w/whisper/whisperv6/whisper.go
|
|
@@ -382,9 +382,9 @@ func (whisper *Whisper) NewKeyPair() (string, error) {
|
|
return "", fmt.Errorf("failed to generate valid key")
|
|
}
|
|
|
|
- id, err := GenerateRandomID()
|
|
+ id, err := toDeterministicID(common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), keyIDSize)
|
|
if err != nil {
|
|
- return "", fmt.Errorf("failed to generate ID: %s", err)
|
|
+ return "", err
|
|
}
|
|
|
|
whisper.keyMu.Lock()
|
|
@@ -399,11 +399,16 @@ func (whisper *Whisper) NewKeyPair() (string, error) {
|
|
|
|
// DeleteKeyPair deletes the specified key if it exists.
|
|
func (whisper *Whisper) DeleteKeyPair(key string) bool {
|
|
+ deterministicID, err := toDeterministicID(key, keyIDSize)
|
|
+ if err != nil {
|
|
+ return false
|
|
+ }
|
|
+
|
|
whisper.keyMu.Lock()
|
|
defer whisper.keyMu.Unlock()
|
|
|
|
- if whisper.privateKeys[key] != nil {
|
|
- delete(whisper.privateKeys, key)
|
|
+ if whisper.privateKeys[deterministicID] != nil {
|
|
+ delete(whisper.privateKeys, deterministicID)
|
|
return true
|
|
}
|
|
return false
|
|
@@ -411,31 +416,73 @@ func (whisper *Whisper) DeleteKeyPair(key string) bool {
|
|
|
|
// AddKeyPair imports a asymmetric private key and returns it identifier.
|
|
func (whisper *Whisper) AddKeyPair(key *ecdsa.PrivateKey) (string, error) {
|
|
- id, err := GenerateRandomID()
|
|
+ id, err := makeDeterministicID(common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), keyIDSize)
|
|
if err != nil {
|
|
- return "", fmt.Errorf("failed to generate ID: %s", err)
|
|
+ return "", err
|
|
+ }
|
|
+ if whisper.HasKeyPair(id) {
|
|
+ return id, nil // no need to re-inject
|
|
}
|
|
|
|
whisper.keyMu.Lock()
|
|
whisper.privateKeys[id] = key
|
|
whisper.keyMu.Unlock()
|
|
+ log.Info("Whisper identity added", "id", id, "pubkey", common.ToHex(crypto.FromECDSAPub(&key.PublicKey)))
|
|
|
|
return id, nil
|
|
}
|
|
|
|
+// SelectKeyPair adds cryptographic identity, and makes sure
|
|
+// that it is the only private key known to the node.
|
|
+func (whisper *Whisper) SelectKeyPair(key *ecdsa.PrivateKey) error {
|
|
+ id, err := makeDeterministicID(common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), keyIDSize)
|
|
+ if err != nil {
|
|
+ return err
|
|
+ }
|
|
+
|
|
+ whisper.keyMu.Lock()
|
|
+ defer whisper.keyMu.Unlock()
|
|
+
|
|
+ whisper.privateKeys = make(map[string]*ecdsa.PrivateKey) // reset key store
|
|
+ whisper.privateKeys[id] = key
|
|
+
|
|
+ log.Info("Whisper identity selected", "id", id, "key", common.ToHex(crypto.FromECDSAPub(&key.PublicKey)))
|
|
+ return nil
|
|
+}
|
|
+
|
|
+// DeleteKeyPairs removes all cryptographic identities known to the node
|
|
+func (whisper *Whisper) DeleteKeyPairs() error {
|
|
+ whisper.keyMu.Lock()
|
|
+ defer whisper.keyMu.Unlock()
|
|
+
|
|
+ whisper.privateKeys = make(map[string]*ecdsa.PrivateKey)
|
|
+
|
|
+ return nil
|
|
+}
|
|
+
|
|
// HasKeyPair checks if the the whisper node is configured with the private key
|
|
// of the specified public pair.
|
|
func (whisper *Whisper) HasKeyPair(id string) bool {
|
|
+ deterministicID, err := toDeterministicID(id, keyIDSize)
|
|
+ if err != nil {
|
|
+ return false
|
|
+ }
|
|
+
|
|
whisper.keyMu.RLock()
|
|
defer whisper.keyMu.RUnlock()
|
|
- return whisper.privateKeys[id] != nil
|
|
+ return whisper.privateKeys[deterministicID] != nil
|
|
}
|
|
|
|
// GetPrivateKey retrieves the private key of the specified identity.
|
|
func (whisper *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
|
|
+ deterministicID, err := toDeterministicID(id, keyIDSize)
|
|
+ if err != nil {
|
|
+ return nil, err
|
|
+ }
|
|
+
|
|
whisper.keyMu.RLock()
|
|
defer whisper.keyMu.RUnlock()
|
|
- key := whisper.privateKeys[id]
|
|
+ key := whisper.privateKeys[deterministicID]
|
|
if key == nil {
|
|
return nil, fmt.Errorf("invalid id")
|
|
}
|
|
@@ -467,6 +514,23 @@ func (whisper *Whisper) GenerateSymKey() (string, error) {
|
|
return id, nil
|
|
}
|
|
|
|
+// AddSymKey stores the key with a given id.
|
|
+func (whisper *Whisper) AddSymKey(id string, key []byte) (string, error) {
|
|
+ deterministicID, err := toDeterministicID(id, keyIDSize)
|
|
+ if err != nil {
|
|
+ return "", err
|
|
+ }
|
|
+
|
|
+ whisper.keyMu.Lock()
|
|
+ defer whisper.keyMu.Unlock()
|
|
+
|
|
+ if whisper.symKeys[deterministicID] != nil {
|
|
+ return "", fmt.Errorf("key already exists: %v", id)
|
|
+ }
|
|
+ whisper.symKeys[deterministicID] = key
|
|
+ return deterministicID, nil
|
|
+}
|
|
+
|
|
// AddSymKeyDirect stores the key, and returns its id.
|
|
func (whisper *Whisper) AddSymKeyDirect(key []byte) (string, error) {
|
|
if len(key) != aesKeyLength {
|
|
@@ -1013,6 +1077,33 @@ func GenerateRandomID() (id string, err error) {
|
|
return id, err
|
|
}
|
|
|
|
+// makeDeterministicID generates a deterministic ID, based on a given input
|
|
+func makeDeterministicID(input string, keyLen int) (id string, err error) {
|
|
+ buf := pbkdf2.Key([]byte(input), nil, 4096, keyLen, sha256.New)
|
|
+ if !validateDataIntegrity(buf, keyIDSize) {
|
|
+ return "", fmt.Errorf("error in GenerateDeterministicID: failed to generate key")
|
|
+ }
|
|
+ id = common.Bytes2Hex(buf)
|
|
+ return id, err
|
|
+}
|
|
+
|
|
+// toDeterministicID reviews incoming id, and transforms it to format
|
|
+// expected internally be private key store. Originally, public keys
|
|
+// were used as keys, now random keys are being used. And in order to
|
|
+// make it easier to consume, we now allow both random IDs and public
|
|
+// keys to be passed.
|
|
+func toDeterministicID(id string, expectedLen int) (string, error) {
|
|
+ if len(id) != (expectedLen * 2) { // we received hex key, so number of chars in id is doubled
|
|
+ var err error
|
|
+ id, err = makeDeterministicID(id, expectedLen)
|
|
+ if err != nil {
|
|
+ return "", err
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return id, nil
|
|
+}
|
|
+
|
|
func isFullNode(bloom []byte) bool {
|
|
if bloom == nil {
|
|
return true
|
|
@@ -1048,3 +1139,15 @@ func addBloom(a, b []byte) []byte {
|
|
}
|
|
return c
|
|
}
|
|
+
|
|
+// SelectedKeyPairID returns the id of currently selected key pair.
|
|
+// It helps distinguish between different users w/o exposing the user identity itself.
|
|
+func (whisper *Whisper) SelectedKeyPairID() string {
|
|
+ whisper.keyMu.RLock()
|
|
+ defer whisper.keyMu.RUnlock()
|
|
+
|
|
+ for id := range whisper.privateKeys {
|
|
+ return id
|
|
+ }
|
|
+ return ""
|
|
+}
|