whisper: sym key management changed

This commit is contained in:
Vlad 2017-03-02 13:38:38 +01:00
parent 581841f74d
commit 8ac7104567
10 changed files with 336 additions and 149 deletions

View file

@ -46,7 +46,6 @@ import (
) )
const quitCommand = "~Q" const quitCommand = "~Q"
const symKeyName = "da919ea33001b04dfc630522e33078ec0df11"
// singletons // singletons
var ( var (
@ -288,8 +287,14 @@ func configureNode() {
} }
} }
shh.AddSymKey(symKeyName, []byte(symPass)) symKeyID, err := shh.AddSymKeyFromPassword(symPass)
symKey = shh.GetSymKey(symKeyName) if err != nil {
utils.Fatalf("Failed to create symmetric key: %s", err)
}
symKey, err = shh.GetSymKey(symKeyID)
if err != nil {
utils.Fatalf("Failed to save symmetric key: %s", err)
}
if len(*argTopic) == 0 { if len(*argTopic) == 0 {
generateTopic([]byte(symPass)) generateTopic([]byte(symPass))
} }
@ -470,11 +475,14 @@ func requestExpiredMessagesLoop() {
var t string var t string
var xt, empty whisper.TopicType var xt, empty whisper.TopicType
err := shh.AddSymKey(mailserver.MailServerKeyName, []byte(msPassword)) keyID, err := shh.AddSymKeyFromPassword(msPassword)
if err != nil { if err != nil {
utils.Fatalf("Failed to create symmetric key for mail request: %s", err) utils.Fatalf("Failed to create symmetric key for mail request: %s", err)
} }
key = shh.GetSymKey(mailserver.MailServerKeyName) key, err = shh.GetSymKey(keyID)
if err != nil {
utils.Fatalf("Failed to save symmetric key for mail request: %s", err)
}
peerID = extractIdFromEnode(*argEnode) peerID = extractIdFromEnode(*argEnode)
shh.MarkPeerTrusted(peerID) shh.MarkPeerTrusted(peerID)

View file

@ -31,8 +31,6 @@ import (
"github.com/syndtr/goleveldb/leveldb/util" "github.com/syndtr/goleveldb/leveldb/util"
) )
const MailServerKeyName = "958e04ab302fb36ad2616a352cbac79d"
type WMailServer struct { type WMailServer struct {
db *leveldb.DB db *leveldb.DB
w *whisper.Whisper w *whisper.Whisper
@ -75,11 +73,14 @@ func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, p
s.w = shh s.w = shh
s.pow = pow s.pow = pow
err = s.w.AddSymKey(MailServerKeyName, []byte(password)) MailServerKeyID, err := s.w.AddSymKeyFromPassword(password)
if err != nil { if err != nil {
utils.Fatalf("Failed to create symmetric key for MailServer: %s", err) utils.Fatalf("Failed to create symmetric key for MailServer: %s", err)
} }
s.key = s.w.GetSymKey(MailServerKeyName) s.key, err = s.w.GetSymKey(MailServerKeyID)
if err != nil {
utils.Fatalf("Failed to save symmetric key for MailServer")
}
} }
func (s *WMailServer) Close() { func (s *WMailServer) Close() {

View file

@ -30,8 +30,8 @@ import (
) )
const powRequirement = 0.00001 const powRequirement = 0.00001
const keyName = "6d604bac5401ce9a6b995f1b45a4ab"
var keyID string
var shh *whisper.Whisper var shh *whisper.Whisper
var seed = time.Now().Unix() var seed = time.Now().Unix()
@ -90,7 +90,7 @@ func TestMailServer(t *testing.T) {
server.Init(shh, dir, password, powRequirement) server.Init(shh, dir, password, powRequirement)
defer server.Close() defer server.Close()
err = shh.AddSymKey(keyName, []byte(password)) keyID, err = shh.AddSymKeyFromPassword(password)
if err != nil { if err != nil {
t.Fatalf("Failed to create symmetric key for mail request: %s", err) t.Fatalf("Failed to create symmetric key for mail request: %s", err)
} }
@ -167,8 +167,13 @@ func createRequest(t *testing.T, p *ServerTestParams) *whisper.Envelope {
binary.BigEndian.PutUint32(data[4:], p.upp) binary.BigEndian.PutUint32(data[4:], p.upp)
copy(data[8:], p.topic[:]) copy(data[8:], p.topic[:])
key, err := shh.GetSymKey(keyID)
if err != nil {
t.Fatalf("failed to retrieve sym key with seed %d: %s.", seed, err)
}
params := &whisper.MessageParams{ params := &whisper.MessageParams{
KeySym: shh.GetSymKey(keyName), KeySym: key,
Topic: p.topic, Topic: p.topic,
Payload: data, Payload: data,
PoW: powRequirement * 2, PoW: powRequirement * 2,

View file

@ -134,40 +134,63 @@ func (api *PublicWhisperAPI) NewIdentity() (string, error) {
return common.ToHex(crypto.FromECDSAPub(&identity.PublicKey)), nil return common.ToHex(crypto.FromECDSAPub(&identity.PublicKey)), nil
} }
// GenerateSymKey generates a random symmetric key and stores it under // todo: implement
// the 'name' id. Will be used in the future for session key exchange. //func (api *PublicWhisperAPI) GetPublicKey(id string) (bool, error) {
func (api *PublicWhisperAPI) GenerateSymKey(name string) error { // if api.whisper == nil {
// return false, whisperOffLineErr
// }
// return api.whisper.HasIdentity(identity), nil
//}
// GenerateSymKey generates a random symmetric key and stores it under id,
// which is then returned. Will be used in the future for session key exchange.
func (api *PublicWhisperAPI) GenerateSymKey() (string, error) {
if api.whisper == nil { if api.whisper == nil {
return whisperOffLineErr return "", whisperOffLineErr
} }
return api.whisper.GenerateSymKey(name) return api.whisper.GenerateSymKey()
} }
// AddSymKey stores the key under the 'name' id. // AddSymKeyDirect stores the key, and returns its id.
func (api *PublicWhisperAPI) AddSymKey(name string, key hexutil.Bytes) error { func (api *PublicWhisperAPI) AddSymKeyDirect(key hexutil.Bytes) (string, error) {
if api.whisper == nil { if api.whisper == nil {
return whisperOffLineErr return "", whisperOffLineErr
} }
return api.whisper.AddSymKey(name, key) return api.whisper.AddSymKeyDirect(key)
} }
// HasSymKey returns true if there is a key associated with the name string. // AddSymKeyFromPassword generates the key from password, stores it, and returns its id.
func (api *PublicWhisperAPI) AddSymKeyFromPassword(password string) (string, error) {
if api.whisper == nil {
return "", whisperOffLineErr
}
return api.whisper.AddSymKeyFromPassword(password)
}
// HasSymKey returns true if there is a key associated with the given id.
// Otherwise returns false. // Otherwise returns false.
func (api *PublicWhisperAPI) HasSymKey(name string) (bool, error) { func (api *PublicWhisperAPI) HasSymKey(id string) (bool, error) {
if api.whisper == nil { if api.whisper == nil {
return false, whisperOffLineErr return false, whisperOffLineErr
} }
res := api.whisper.HasSymKey(name) res := api.whisper.HasSymKey(id)
return res, nil return res, nil
} }
// DeleteSymKey deletes the key associated with the name string if it exists. func (api *PublicWhisperAPI) GetSymKey(name string) ([]byte, error) {
func (api *PublicWhisperAPI) DeleteSymKey(name string) error {
if api.whisper == nil { if api.whisper == nil {
return whisperOffLineErr return nil, whisperOffLineErr
} }
api.whisper.DeleteSymKey(name) return api.whisper.GetSymKey(name)
return nil }
// DeleteSymKey deletes the key associated with the name string if it exists.
func (api *PublicWhisperAPI) DeleteSymKey(name string) (bool, error) {
if api.whisper == nil {
return false, whisperOffLineErr
}
res := api.whisper.DeleteSymKey(name)
return res, nil
} }
// NewWhisperFilter creates and registers a new message filter to watch for inbound whisper messages. // NewWhisperFilter creates and registers a new message filter to watch for inbound whisper messages.
@ -177,9 +200,21 @@ func (api *PublicWhisperAPI) NewFilter(args WhisperFilterArgs) (string, error) {
return "", whisperOffLineErr return "", whisperOffLineErr
} }
var err error
var symKey []byte
if len(args.KeyName) > 0 {
symKey, err = api.whisper.GetSymKey(args.KeyName)
if err != nil {
info := "NewFilter: symmetric key ID does not exist: " + args.KeyName
log.Error(fmt.Sprintf(info))
return "", errors.New(info)
}
}
filter := Filter{ filter := Filter{
Src: crypto.ToECDSAPub(common.FromHex(args.From)), Src: crypto.ToECDSAPub(common.FromHex(args.From)),
KeySym: api.whisper.GetSymKey(args.KeyName), KeySym: symKey,
PoW: args.PoW, PoW: args.PoW,
Messages: make(map[common.Hash]*ReceivedMessage), Messages: make(map[common.Hash]*ReceivedMessage),
AcceptP2P: args.AcceptP2P, AcceptP2P: args.AcceptP2P,
@ -195,12 +230,6 @@ func (api *PublicWhisperAPI) NewFilter(args WhisperFilterArgs) (string, error) {
return "", errors.New(info) return "", errors.New(info)
} }
if len(args.KeyName) != 0 && len(filter.KeySym) == 0 {
info := "NewFilter: key was not found by name: " + args.KeyName
log.Error(fmt.Sprintf(info))
return "", errors.New(info)
}
if len(args.To) == 0 && len(filter.KeySym) == 0 { if len(args.To) == 0 && len(filter.KeySym) == 0 {
info := "NewFilter: filter must contain either symmetric or asymmetric key" info := "NewFilter: filter must contain either symmetric or asymmetric key"
log.Error(fmt.Sprintf(info)) log.Error(fmt.Sprintf(info))
@ -275,10 +304,22 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
return whisperOffLineErr return whisperOffLineErr
} }
var err error
var symKey []byte
if len(args.KeyName) > 0 {
symKey, err = api.whisper.GetSymKey(args.KeyName)
if err != nil {
info := "NewFilter: symmetric key ID does not exist: " + args.KeyName
log.Error(fmt.Sprintf(info))
return errors.New(info)
}
}
params := MessageParams{ params := MessageParams{
TTL: args.TTL, TTL: args.TTL,
Dst: crypto.ToECDSAPub(common.FromHex(args.To)), Dst: crypto.ToECDSAPub(common.FromHex(args.To)),
KeySym: api.whisper.GetSymKey(args.KeyName), KeySym: symKey,
Topic: args.Topic, Topic: args.Topic,
Payload: args.Payload, Payload: args.Payload,
Padding: args.Padding, Padding: args.Padding,
@ -333,12 +374,6 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
} }
// validate // validate
if len(args.KeyName) != 0 && len(params.KeySym) == 0 {
info := "Post: key was not found by name: " + args.KeyName
log.Error(fmt.Sprintf(info))
return errors.New(info)
}
if len(args.To) == 0 && len(params.KeySym) == 0 { if len(args.To) == 0 && len(params.KeySym) == 0 {
info := "Post: message must be encrypted either symmetrically or asymmetrically" info := "Post: message must be encrypted either symmetrically or asymmetrically"
log.Error(fmt.Sprintf(info)) log.Error(fmt.Sprintf(info))

View file

@ -106,7 +106,7 @@ func TestBasic(t *testing.T) {
t.Fatalf("failed HasSymKey: false positive.") t.Fatalf("failed HasSymKey: false positive.")
} }
err = api.GenerateSymKey(id) id, err = api.GenerateSymKey()
if err != nil { if err != nil {
t.Fatalf("failed GenerateSymKey: %s.", err) t.Fatalf("failed GenerateSymKey: %s.", err)
} }
@ -119,12 +119,13 @@ func TestBasic(t *testing.T) {
t.Fatalf("failed HasSymKey(): false negative.") t.Fatalf("failed HasSymKey(): false negative.")
} }
err = api.AddSymKey(id, []byte("some stuff here")) const password = "some stuff here"
if err == nil { id, err = api.AddSymKeyFromPassword(password)
if err != nil {
t.Fatalf("failed AddSymKey: %s.", err) t.Fatalf("failed AddSymKey: %s.", err)
} }
err = api.AddSymKey(id2, []byte("some stuff here")) id2, err = api.AddSymKeyFromPassword(password)
if err != nil { if err != nil {
t.Fatalf("failed AddSymKey: %s.", err) t.Fatalf("failed AddSymKey: %s.", err)
} }
@ -137,10 +138,26 @@ func TestBasic(t *testing.T) {
t.Fatalf("failed HasSymKey(id2): false negative.") t.Fatalf("failed HasSymKey(id2): false negative.")
} }
err = api.DeleteSymKey(id) k1, err := api.GetSymKey(id)
if err != nil {
t.Fatalf("failed GetSymKey(id): %s.", err)
}
k2, err := api.GetSymKey(id2)
if err != nil {
t.Fatalf("failed GetSymKey(id2): %s.", err)
}
if !bytes.Equal(k1, k2) {
t.Fatalf("installed keys are not equal")
}
exist, err = api.DeleteSymKey(id)
if err != nil { if err != nil {
t.Fatalf("failed DeleteSymKey(id): %s.", err) t.Fatalf("failed DeleteSymKey(id): %s.", err)
} }
if !exist {
t.Fatalf("failed DeleteSymKey(id): false negative.")
}
exist, err = api.HasSymKey(id) exist, err = api.HasSymKey(id)
if err != nil { if err != nil {
@ -384,8 +401,7 @@ func TestIntegrationSym(t *testing.T) {
api.Start() api.Start()
defer api.Stop() defer api.Stop()
keyname := "schluessel" keyID, err := api.GenerateSymKey()
err := api.GenerateSymKey(keyname)
if err != nil { if err != nil {
t.Fatalf("failed GenerateSymKey: %s.", err) t.Fatalf("failed GenerateSymKey: %s.", err)
} }
@ -410,7 +426,7 @@ func TestIntegrationSym(t *testing.T) {
topics[0] = TopicType{0x00, 0x7f, 0x80, 0xff} topics[0] = TopicType{0x00, 0x7f, 0x80, 0xff}
topics[1] = TopicType{0xf2, 0x6e, 0x77, 0x79} topics[1] = TopicType{0xf2, 0x6e, 0x77, 0x79}
var f WhisperFilterArgs var f WhisperFilterArgs
f.KeyName = keyname f.KeyName = keyID
f.Topics = topics[:] f.Topics = topics[:]
f.PoW = 0.324 f.PoW = 0.324
f.From = sig f.From = sig
@ -423,7 +439,7 @@ func TestIntegrationSym(t *testing.T) {
var p PostArgs var p PostArgs
p.TTL = 1 p.TTL = 1
p.KeyName = keyname p.KeyName = keyID
p.From = f.From p.From = f.From
p.Padding = []byte("test string") p.Padding = []byte("test string")
p.Payload = []byte("extended test string") p.Payload = []byte("extended test string")
@ -474,8 +490,7 @@ func TestIntegrationSymWithFilter(t *testing.T) {
api.Start() api.Start()
defer api.Stop() defer api.Stop()
keyname := "schluessel" keyID, err := api.GenerateSymKey()
err := api.GenerateSymKey(keyname)
if err != nil { if err != nil {
t.Fatalf("failed to GenerateSymKey: %s.", err) t.Fatalf("failed to GenerateSymKey: %s.", err)
} }
@ -500,7 +515,7 @@ func TestIntegrationSymWithFilter(t *testing.T) {
topics[0] = TopicType{0x00, 0x7f, 0x80, 0xff} topics[0] = TopicType{0x00, 0x7f, 0x80, 0xff}
topics[1] = TopicType{0xf2, 0x6e, 0x77, 0x79} topics[1] = TopicType{0xf2, 0x6e, 0x77, 0x79}
var f WhisperFilterArgs var f WhisperFilterArgs
f.KeyName = keyname f.KeyName = keyID
f.Topics = topics[:] f.Topics = topics[:]
f.PoW = 0.324 f.PoW = 0.324
f.From = sig f.From = sig

View file

@ -54,6 +54,7 @@ const (
aesKeyLength = 32 aesKeyLength = 32
saltLength = 12 saltLength = 12
AESNonceMaxLength = 12 AESNonceMaxLength = 12
keyIdSize = 32
DefaultMaxMessageLength = 1024 * 1024 DefaultMaxMessageLength = 1024 * 1024
DefaultMinimumPoW = 10.0 // todo: review after testing. DefaultMinimumPoW = 10.0 // todo: review after testing.

View file

@ -18,7 +18,6 @@ package whisperv5
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
crand "crypto/rand"
"fmt" "fmt"
"sync" "sync"
@ -52,40 +51,24 @@ func NewFilters(w *Whisper) *Filters {
} }
} }
func (fs *Filters) generateRandomID() (id string, err error) {
buf := make([]byte, 20)
for i := 0; i < 3; i++ {
_, err = crand.Read(buf)
if err != nil {
continue
}
if !validateSymmetricKey(buf) {
err = fmt.Errorf("error in generateRandomID: crypto/rand failed to generate random data")
continue
}
id = common.Bytes2Hex(buf)
if fs.watchers[id] != nil {
err = fmt.Errorf("error in generateRandomID: generated same ID twice")
continue
}
return id, err
}
return "", err
}
func (fs *Filters) Install(watcher *Filter) (string, error) { func (fs *Filters) Install(watcher *Filter) (string, error) {
if watcher.Messages == nil { if watcher.Messages == nil {
watcher.Messages = make(map[common.Hash]*ReceivedMessage) watcher.Messages = make(map[common.Hash]*ReceivedMessage)
} }
id, err := GenerateRandomID()
if err != nil {
return "", err
}
fs.mutex.Lock() fs.mutex.Lock()
defer fs.mutex.Unlock() defer fs.mutex.Unlock()
id, err := fs.generateRandomID() if fs.watchers[id] != nil {
if err == nil { return "", fmt.Errorf("failed to generate unique ID")
fs.watchers[id] = watcher
} }
fs.watchers[id] = watcher
return id, err return id, err
} }

View file

@ -108,7 +108,7 @@ func TestInstallFilters(t *testing.T) {
t.Fatalf("seed %d: failed to install filter: %s", seed, err) t.Fatalf("seed %d: failed to install filter: %s", seed, err)
} }
tst[i].id = j tst[i].id = j
if len(j) != 40 { if len(j) != keyIdSize*2 {
t.Fatalf("seed %d: wrong filter id size [%d]", seed, len(j)) t.Fatalf("seed %d: wrong filter id size [%d]", seed, len(j))
} }
} }

View file

@ -48,8 +48,9 @@ type Whisper struct {
filters *Filters filters *Filters
privateKeys map[string]*ecdsa.PrivateKey privateKeys map[string]*ecdsa.PrivateKey
symKeys map[string][]byte //identities map[string]*ecdsa.PrivateKey
keyMu sync.RWMutex symKeys map[string][]byte
keyMu sync.RWMutex
envelopes map[common.Hash]*Envelope // Pool of envelopes currently tracked by this node envelopes map[common.Hash]*Envelope // Pool of envelopes currently tracked by this node
expirations map[uint32]*set.SetNonTS // Message expiration pool expirations map[uint32]*set.SetNonTS // Message expiration pool
@ -75,7 +76,8 @@ type Whisper struct {
// Param s should be passed if you want to implement mail server, otherwise nil. // Param s should be passed if you want to implement mail server, otherwise nil.
func New() *Whisper { func New() *Whisper {
whisper := &Whisper{ whisper := &Whisper{
privateKeys: make(map[string]*ecdsa.PrivateKey), privateKeys: make(map[string]*ecdsa.PrivateKey),
//identities: make(map[string]*ecdsa.PrivateKey),
symKeys: make(map[string][]byte), symKeys: make(map[string][]byte),
envelopes: make(map[common.Hash]*Envelope), envelopes: make(map[common.Hash]*Envelope),
expirations: make(map[uint32]*set.SetNonTS), expirations: make(map[uint32]*set.SetNonTS),
@ -231,72 +233,108 @@ func (w *Whisper) GetIdentity(pubKey string) *ecdsa.PrivateKey {
return w.privateKeys[pubKey] return w.privateKeys[pubKey]
} }
func (w *Whisper) GenerateSymKey(name string) error { func (w *Whisper) GenerateSymKey() (string, error) {
const size = aesKeyLength * 2 const size = aesKeyLength * 2
buf := make([]byte, size) buf := make([]byte, size)
_, err := crand.Read(buf) _, err := crand.Read(buf)
if err != nil { if err != nil {
return err return "", err
} else if !validateSymmetricKey(buf) { } else if !validateSymmetricKey(buf) {
return fmt.Errorf("error in GenerateSymKey: crypto/rand failed to generate random data") return "", fmt.Errorf("error in GenerateSymKey: crypto/rand failed to generate random data")
} }
key := buf[:aesKeyLength] key := buf[:aesKeyLength]
salt := buf[aesKeyLength:] salt := buf[aesKeyLength:]
derived, err := DeriveOneTimeKey(key, salt, EnvelopeVersion) derived, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
if err != nil { if err != nil {
return err return "", err
} else if !validateSymmetricKey(derived) { } else if !validateSymmetricKey(derived) {
return fmt.Errorf("failed to derive valid key") return "", fmt.Errorf("failed to derive valid key")
} }
w.keyMu.Lock() id, err := GenerateRandomID()
defer w.keyMu.Unlock()
if w.symKeys[name] != nil {
return fmt.Errorf("Key with name [%s] already exists", name)
}
w.symKeys[name] = derived
return nil
}
func (w *Whisper) AddSymKey(name string, key []byte) error {
if w.HasSymKey(name) {
return fmt.Errorf("Key with name [%s] already exists", name)
}
derived, err := deriveKeyMaterial(key, EnvelopeVersion)
if err != nil { if err != nil {
return err return "", fmt.Errorf("Failed to generate ID: %s", err)
} }
w.keyMu.Lock() w.keyMu.Lock()
defer w.keyMu.Unlock() defer w.keyMu.Unlock()
// double check is necessary, because deriveKeyMaterial() is slow if w.symKeys[id] != nil {
if w.symKeys[name] != nil { return "", fmt.Errorf("Failed to generate unique ID")
return fmt.Errorf("Key with name [%s] already exists", name)
} }
w.symKeys[name] = derived w.symKeys[id] = derived
return nil return id, nil
} }
func (w *Whisper) HasSymKey(name string) bool { func (w *Whisper) AddSymKeyDirect(key []byte) (string, error) {
w.keyMu.RLock() if len(key) != aesKeyLength {
defer w.keyMu.RUnlock() return "", fmt.Errorf("Wrong key size: %d", len(key))
return w.symKeys[name] != nil }
}
id, err := GenerateRandomID()
if err != nil {
return "", fmt.Errorf("Failed to generate ID: %s", err)
}
func (w *Whisper) DeleteSymKey(name string) {
w.keyMu.Lock() w.keyMu.Lock()
defer w.keyMu.Unlock() defer w.keyMu.Unlock()
delete(w.symKeys, name)
if w.symKeys[id] != nil {
return "", fmt.Errorf("Failed to generate unique ID")
}
w.symKeys[id] = key
return id, nil
} }
func (w *Whisper) GetSymKey(name string) []byte { func (w *Whisper) AddSymKeyFromPassword(password string) (string, error) {
id, err := GenerateRandomID()
if err != nil {
return "", fmt.Errorf("Failed to generate ID: %s", err)
}
if w.HasSymKey(id) {
return "", fmt.Errorf("Failed to generate unique ID")
}
derived, err := deriveKeyMaterial([]byte(password), EnvelopeVersion)
if err != nil {
return "", err
}
w.keyMu.Lock()
defer w.keyMu.Unlock()
// double check is necessary, because deriveKeyMaterial() is very slow
if w.symKeys[id] != nil {
return "", fmt.Errorf("Severe error: failed to generate unique ID")
}
w.symKeys[id] = derived
return id, nil
}
func (w *Whisper) HasSymKey(id string) bool {
w.keyMu.RLock() w.keyMu.RLock()
defer w.keyMu.RUnlock() defer w.keyMu.RUnlock()
return w.symKeys[name] return w.symKeys[id] != nil
}
func (w *Whisper) DeleteSymKey(id string) bool {
w.keyMu.Lock()
defer w.keyMu.Unlock()
if w.symKeys[id] != nil {
delete(w.symKeys, id)
return true
}
return false
}
func (w *Whisper) GetSymKey(id string) ([]byte, error) {
w.keyMu.RLock()
defer w.keyMu.RUnlock()
if w.symKeys[id] != nil {
return w.symKeys[id], nil
}
return nil, fmt.Errorf("non-existent ID")
} }
// Watch installs a new message handler to run in case a matching packet arrives // Watch installs a new message handler to run in case a matching packet arrives
@ -709,3 +747,16 @@ func deriveKeyMaterial(key []byte, version uint64) (derivedKey []byte, err error
return nil, unknownVersionError(version) return nil, unknownVersionError(version)
} }
} }
func GenerateRandomID() (id string, err error) {
buf := make([]byte, keyIdSize)
_, err = crand.Read(buf)
if err != nil {
return "", err
}
if !validateSymmetricKey(buf) {
return "", fmt.Errorf("error in generateRandomID: crypto/rand failed to generate random data")
}
id = common.Bytes2Hex(buf)
return id, err
}

View file

@ -61,9 +61,12 @@ func TestWhisperBasic(t *testing.T) {
if exist { if exist {
t.Fatalf("failed HasSymKey.") t.Fatalf("failed HasSymKey.")
} }
key := w.GetSymKey("non-existing") key, err := w.GetSymKey("non-existing")
if err == nil {
t.Fatalf("failed GetSymKey(non-existing): false positive.")
}
if key != nil { if key != nil {
t.Fatalf("failed GetSymKey.") t.Fatalf("failed GetSymKey: false positive.")
} }
mail := w.Envelopes() mail := w.Envelopes()
if len(mail) != 0 { if len(mail) != 0 {
@ -79,7 +82,7 @@ func TestWhisperBasic(t *testing.T) {
if _, err := deriveKeyMaterial(peerID, ver); err != unknownVersionError(ver) { if _, err := deriveKeyMaterial(peerID, ver); err != unknownVersionError(ver) {
t.Fatalf("failed deriveKeyMaterial with param = %v: %s.", peerID, err) t.Fatalf("failed deriveKeyMaterial with param = %v: %s.", peerID, err)
} }
derived, err := deriveKeyMaterial(peerID, 0) derived, err = deriveKeyMaterial(peerID, 0)
if err != nil { if err != nil {
t.Fatalf("failed second deriveKeyMaterial with param = %v: %s.", peerID, err) t.Fatalf("failed second deriveKeyMaterial with param = %v: %s.", peerID, err)
} }
@ -185,23 +188,30 @@ func TestWhisperIdentityManagement(t *testing.T) {
func TestWhisperSymKeyManagement(t *testing.T) { func TestWhisperSymKeyManagement(t *testing.T) {
InitSingleTest() InitSingleTest()
var err error
var k1, k2 []byte var k1, k2 []byte
w := New() w := New()
id1 := string("arbitrary-string-1") id1 := string("arbitrary-string-1")
id2 := string("arbitrary-string-2") id2 := string("arbitrary-string-2")
err := w.GenerateSymKey(id1) id1, err = w.GenerateSymKey()
if err != nil { if err != nil {
t.Fatalf("failed GenerateSymKey with seed %d: %s.", seed, err) t.Fatalf("failed GenerateSymKey with seed %d: %s.", seed, err)
} }
k1 = w.GetSymKey(id1) k1, err = w.GetSymKey(id1)
k2 = w.GetSymKey(id2) if err != nil {
t.Fatalf("failed GetSymKey(id1).")
}
k2, err = w.GetSymKey(id2)
if err == nil {
t.Fatalf("failed GetSymKey(id2): false positive.")
}
if !w.HasSymKey(id1) { if !w.HasSymKey(id1) {
t.Fatalf("failed HasSymKey(id1).") t.Fatalf("failed HasSymKey(id1).")
} }
if w.HasSymKey(id2) { if w.HasSymKey(id2) {
t.Fatalf("failed HasSymKey(id2).") t.Fatalf("failed HasSymKey(id2): false positive.")
} }
if k1 == nil { if k1 == nil {
t.Fatalf("first key does not exist.") t.Fatalf("first key does not exist.")
@ -210,38 +220,49 @@ func TestWhisperSymKeyManagement(t *testing.T) {
t.Fatalf("second key still exist.") t.Fatalf("second key still exist.")
} }
// add existing id, nothing should change randomKey := make([]byte, aesKeyLength)
randomKey := make([]byte, 16)
randomize(randomKey) randomize(randomKey)
err = w.AddSymKey(id1, randomKey) id1, err = w.AddSymKeyDirect(randomKey)
if err == nil { if err != nil {
t.Fatalf("failed AddSymKey with seed %d.", seed) t.Fatalf("failed AddSymKey with seed %d: %s.", seed, err)
} }
k1 = w.GetSymKey(id1) k1, err = w.GetSymKey(id1)
k2 = w.GetSymKey(id2) if err != nil {
t.Fatalf("failed w.GetSymKey(id1).")
}
k2, err = w.GetSymKey(id2)
if err == nil {
t.Fatalf("failed w.GetSymKey(id2): false positive.")
}
if !w.HasSymKey(id1) { if !w.HasSymKey(id1) {
t.Fatalf("failed w.HasSymKey(id1).") t.Fatalf("failed w.HasSymKey(id1).")
} }
if w.HasSymKey(id2) { if w.HasSymKey(id2) {
t.Fatalf("failed w.HasSymKey(id2).") t.Fatalf("failed w.HasSymKey(id2): false positive.")
} }
if k1 == nil { if k1 == nil {
t.Fatalf("first key does not exist.") t.Fatalf("first key does not exist.")
} }
if bytes.Equal(k1, randomKey) { if !bytes.Equal(k1, randomKey) {
t.Fatalf("k1 == randomKey.") t.Fatalf("k1 != randomKey.")
} }
if k2 != nil { if k2 != nil {
t.Fatalf("second key already exist.") t.Fatalf("second key already exist.")
} }
err = w.AddSymKey(id2, randomKey) // add non-existing (yet) id2, err = w.AddSymKeyDirect(randomKey)
if err != nil { if err != nil {
t.Fatalf("failed AddSymKey(id2) with seed %d: %s.", seed, err) t.Fatalf("failed AddSymKey(id2) with seed %d: %s.", seed, err)
} }
k1 = w.GetSymKey(id1) k1, err = w.GetSymKey(id1)
k2 = w.GetSymKey(id2) if err != nil {
t.Fatalf("failed w.GetSymKey(id1).")
}
k2, err = w.GetSymKey(id2)
if err != nil {
t.Fatalf("failed w.GetSymKey(id2).")
}
if !w.HasSymKey(id1) { if !w.HasSymKey(id1) {
t.Fatalf("HasSymKey(id1) failed.") t.Fatalf("HasSymKey(id1) failed.")
} }
@ -254,11 +275,11 @@ func TestWhisperSymKeyManagement(t *testing.T) {
if k2 == nil { if k2 == nil {
t.Fatalf("k2 does not exist.") t.Fatalf("k2 does not exist.")
} }
if bytes.Equal(k1, k2) { if !bytes.Equal(k1, k2) {
t.Fatalf("k1 == k2.") t.Fatalf("k1 != k2.")
} }
if bytes.Equal(k1, randomKey) { if !bytes.Equal(k1, randomKey) {
t.Fatalf("k1 == randomKey.") t.Fatalf("k1 != randomKey.")
} }
if len(k1) != aesKeyLength { if len(k1) != aesKeyLength {
t.Fatalf("wrong length of k1.") t.Fatalf("wrong length of k1.")
@ -268,8 +289,17 @@ func TestWhisperSymKeyManagement(t *testing.T) {
} }
w.DeleteSymKey(id1) w.DeleteSymKey(id1)
k1 = w.GetSymKey(id1) k1, err = w.GetSymKey(id1)
k2 = w.GetSymKey(id2) if err == nil {
t.Fatalf("failed w.GetSymKey(id1): false positive.")
}
if k1 != nil {
t.Fatalf("failed GetSymKey(id1): false positive.")
}
k2, err = w.GetSymKey(id2)
if err != nil {
t.Fatalf("failed w.GetSymKey(id2).")
}
if w.HasSymKey(id1) { if w.HasSymKey(id1) {
t.Fatalf("failed to delete first key: still exist.") t.Fatalf("failed to delete first key: still exist.")
} }
@ -285,8 +315,17 @@ func TestWhisperSymKeyManagement(t *testing.T) {
w.DeleteSymKey(id1) w.DeleteSymKey(id1)
w.DeleteSymKey(id2) w.DeleteSymKey(id2)
k1 = w.GetSymKey(id1) k1, err = w.GetSymKey(id1)
k2 = w.GetSymKey(id2) if err == nil {
t.Fatalf("failed w.GetSymKey(id1): false positive.")
}
k2, err = w.GetSymKey(id2)
if err == nil {
t.Fatalf("failed w.GetSymKey(id2): false positive.")
}
if k1 != nil || k2 != nil {
t.Fatalf("k1 or k2 is not nil")
}
if w.HasSymKey(id1) { if w.HasSymKey(id1) {
t.Fatalf("failed to delete second key: first key exist.") t.Fatalf("failed to delete second key: first key exist.")
} }
@ -299,6 +338,55 @@ func TestWhisperSymKeyManagement(t *testing.T) {
if k2 != nil { if k2 != nil {
t.Fatalf("failed to delete second key: second key is not nil.") t.Fatalf("failed to delete second key: second key is not nil.")
} }
randomKey = make([]byte, aesKeyLength+1)
randomize(randomKey)
id1, err = w.AddSymKeyDirect(randomKey)
if err == nil {
t.Fatalf("added the key with wrong size, seed %d.", seed)
}
const password = "arbitrary data here"
id1, err = w.AddSymKeyFromPassword(password)
if err != nil {
t.Fatalf("failed AddSymKeyFromPassword(id1) with seed %d: %s.", seed, err)
}
id2, err = w.AddSymKeyFromPassword(password)
if err != nil {
t.Fatalf("failed AddSymKeyFromPassword(id2) with seed %d: %s.", seed, err)
}
k1, err = w.GetSymKey(id1)
if err != nil {
t.Fatalf("failed w.GetSymKey(id1).")
}
k2, err = w.GetSymKey(id2)
if err != nil {
t.Fatalf("failed w.GetSymKey(id2).")
}
if !w.HasSymKey(id1) {
t.Fatalf("HasSymKey(id1) failed.")
}
if !w.HasSymKey(id2) {
t.Fatalf("HasSymKey(id2) failed.")
}
if k1 == nil {
t.Fatalf("k1 does not exist.")
}
if k2 == nil {
t.Fatalf("k2 does not exist.")
}
if !bytes.Equal(k1, k2) {
t.Fatalf("k1 != k2.")
}
if len(k1) != aesKeyLength {
t.Fatalf("wrong length of k1.")
}
if len(k2) != aesKeyLength {
t.Fatalf("wrong length of k2.")
}
if !validateSymmetricKey(k2) {
t.Fatalf("key validation failed.")
}
} }
func TestExpiry(t *testing.T) { func TestExpiry(t *testing.T) {