mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
whisper: sym key management changed
This commit is contained in:
parent
581841f74d
commit
8ac7104567
10 changed files with 336 additions and 149 deletions
|
|
@ -46,7 +46,6 @@ import (
|
|||
)
|
||||
|
||||
const quitCommand = "~Q"
|
||||
const symKeyName = "da919ea33001b04dfc630522e33078ec0df11"
|
||||
|
||||
// singletons
|
||||
var (
|
||||
|
|
@ -288,8 +287,14 @@ func configureNode() {
|
|||
}
|
||||
}
|
||||
|
||||
shh.AddSymKey(symKeyName, []byte(symPass))
|
||||
symKey = shh.GetSymKey(symKeyName)
|
||||
symKeyID, err := shh.AddSymKeyFromPassword(symPass)
|
||||
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 {
|
||||
generateTopic([]byte(symPass))
|
||||
}
|
||||
|
|
@ -470,11 +475,14 @@ func requestExpiredMessagesLoop() {
|
|||
var t string
|
||||
var xt, empty whisper.TopicType
|
||||
|
||||
err := shh.AddSymKey(mailserver.MailServerKeyName, []byte(msPassword))
|
||||
keyID, err := shh.AddSymKeyFromPassword(msPassword)
|
||||
if err != nil {
|
||||
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)
|
||||
shh.MarkPeerTrusted(peerID)
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ import (
|
|||
"github.com/syndtr/goleveldb/leveldb/util"
|
||||
)
|
||||
|
||||
const MailServerKeyName = "958e04ab302fb36ad2616a352cbac79d"
|
||||
|
||||
type WMailServer struct {
|
||||
db *leveldb.DB
|
||||
w *whisper.Whisper
|
||||
|
|
@ -75,11 +73,14 @@ func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, p
|
|||
s.w = shh
|
||||
s.pow = pow
|
||||
|
||||
err = s.w.AddSymKey(MailServerKeyName, []byte(password))
|
||||
MailServerKeyID, err := s.w.AddSymKeyFromPassword(password)
|
||||
if err != nil {
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ import (
|
|||
)
|
||||
|
||||
const powRequirement = 0.00001
|
||||
const keyName = "6d604bac5401ce9a6b995f1b45a4ab"
|
||||
|
||||
var keyID string
|
||||
var shh *whisper.Whisper
|
||||
var seed = time.Now().Unix()
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ func TestMailServer(t *testing.T) {
|
|||
server.Init(shh, dir, password, powRequirement)
|
||||
defer server.Close()
|
||||
|
||||
err = shh.AddSymKey(keyName, []byte(password))
|
||||
keyID, err = shh.AddSymKeyFromPassword(password)
|
||||
if err != nil {
|
||||
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)
|
||||
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{
|
||||
KeySym: shh.GetSymKey(keyName),
|
||||
KeySym: key,
|
||||
Topic: p.topic,
|
||||
Payload: data,
|
||||
PoW: powRequirement * 2,
|
||||
|
|
|
|||
|
|
@ -134,40 +134,63 @@ func (api *PublicWhisperAPI) NewIdentity() (string, error) {
|
|||
return common.ToHex(crypto.FromECDSAPub(&identity.PublicKey)), nil
|
||||
}
|
||||
|
||||
// GenerateSymKey generates a random symmetric key and stores it under
|
||||
// the 'name' id. Will be used in the future for session key exchange.
|
||||
func (api *PublicWhisperAPI) GenerateSymKey(name string) error {
|
||||
// todo: implement
|
||||
//func (api *PublicWhisperAPI) GetPublicKey(id string) (bool, 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 {
|
||||
return whisperOffLineErr
|
||||
return "", whisperOffLineErr
|
||||
}
|
||||
return api.whisper.GenerateSymKey(name)
|
||||
return api.whisper.GenerateSymKey()
|
||||
}
|
||||
|
||||
// AddSymKey stores the key under the 'name' id.
|
||||
func (api *PublicWhisperAPI) AddSymKey(name string, key hexutil.Bytes) error {
|
||||
// AddSymKeyDirect stores the key, and returns its id.
|
||||
func (api *PublicWhisperAPI) AddSymKeyDirect(key hexutil.Bytes) (string, error) {
|
||||
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.
|
||||
func (api *PublicWhisperAPI) HasSymKey(name string) (bool, error) {
|
||||
func (api *PublicWhisperAPI) HasSymKey(id string) (bool, error) {
|
||||
if api.whisper == nil {
|
||||
return false, whisperOffLineErr
|
||||
}
|
||||
res := api.whisper.HasSymKey(name)
|
||||
res := api.whisper.HasSymKey(id)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// DeleteSymKey deletes the key associated with the name string if it exists.
|
||||
func (api *PublicWhisperAPI) DeleteSymKey(name string) error {
|
||||
func (api *PublicWhisperAPI) GetSymKey(name string) ([]byte, error) {
|
||||
if api.whisper == nil {
|
||||
return whisperOffLineErr
|
||||
return nil, whisperOffLineErr
|
||||
}
|
||||
api.whisper.DeleteSymKey(name)
|
||||
return nil
|
||||
return api.whisper.GetSymKey(name)
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
|
@ -177,9 +200,21 @@ func (api *PublicWhisperAPI) NewFilter(args WhisperFilterArgs) (string, error) {
|
|||
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{
|
||||
Src: crypto.ToECDSAPub(common.FromHex(args.From)),
|
||||
KeySym: api.whisper.GetSymKey(args.KeyName),
|
||||
KeySym: symKey,
|
||||
PoW: args.PoW,
|
||||
Messages: make(map[common.Hash]*ReceivedMessage),
|
||||
AcceptP2P: args.AcceptP2P,
|
||||
|
|
@ -195,12 +230,6 @@ func (api *PublicWhisperAPI) NewFilter(args WhisperFilterArgs) (string, error) {
|
|||
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 {
|
||||
info := "NewFilter: filter must contain either symmetric or asymmetric key"
|
||||
log.Error(fmt.Sprintf(info))
|
||||
|
|
@ -275,10 +304,22 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
|
|||
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{
|
||||
TTL: args.TTL,
|
||||
Dst: crypto.ToECDSAPub(common.FromHex(args.To)),
|
||||
KeySym: api.whisper.GetSymKey(args.KeyName),
|
||||
KeySym: symKey,
|
||||
Topic: args.Topic,
|
||||
Payload: args.Payload,
|
||||
Padding: args.Padding,
|
||||
|
|
@ -333,12 +374,6 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
info := "Post: message must be encrypted either symmetrically or asymmetrically"
|
||||
log.Error(fmt.Sprintf(info))
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ func TestBasic(t *testing.T) {
|
|||
t.Fatalf("failed HasSymKey: false positive.")
|
||||
}
|
||||
|
||||
err = api.GenerateSymKey(id)
|
||||
id, err = api.GenerateSymKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed GenerateSymKey: %s.", err)
|
||||
}
|
||||
|
|
@ -119,12 +119,13 @@ func TestBasic(t *testing.T) {
|
|||
t.Fatalf("failed HasSymKey(): false negative.")
|
||||
}
|
||||
|
||||
err = api.AddSymKey(id, []byte("some stuff here"))
|
||||
if err == nil {
|
||||
const password = "some stuff here"
|
||||
id, err = api.AddSymKeyFromPassword(password)
|
||||
if err != nil {
|
||||
t.Fatalf("failed AddSymKey: %s.", err)
|
||||
}
|
||||
|
||||
err = api.AddSymKey(id2, []byte("some stuff here"))
|
||||
id2, err = api.AddSymKeyFromPassword(password)
|
||||
if err != nil {
|
||||
t.Fatalf("failed AddSymKey: %s.", err)
|
||||
}
|
||||
|
|
@ -137,10 +138,26 @@ func TestBasic(t *testing.T) {
|
|||
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 {
|
||||
t.Fatalf("failed DeleteSymKey(id): %s.", err)
|
||||
}
|
||||
if !exist {
|
||||
t.Fatalf("failed DeleteSymKey(id): false negative.")
|
||||
}
|
||||
|
||||
exist, err = api.HasSymKey(id)
|
||||
if err != nil {
|
||||
|
|
@ -384,8 +401,7 @@ func TestIntegrationSym(t *testing.T) {
|
|||
api.Start()
|
||||
defer api.Stop()
|
||||
|
||||
keyname := "schluessel"
|
||||
err := api.GenerateSymKey(keyname)
|
||||
keyID, err := api.GenerateSymKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed GenerateSymKey: %s.", err)
|
||||
}
|
||||
|
|
@ -410,7 +426,7 @@ func TestIntegrationSym(t *testing.T) {
|
|||
topics[0] = TopicType{0x00, 0x7f, 0x80, 0xff}
|
||||
topics[1] = TopicType{0xf2, 0x6e, 0x77, 0x79}
|
||||
var f WhisperFilterArgs
|
||||
f.KeyName = keyname
|
||||
f.KeyName = keyID
|
||||
f.Topics = topics[:]
|
||||
f.PoW = 0.324
|
||||
f.From = sig
|
||||
|
|
@ -423,7 +439,7 @@ func TestIntegrationSym(t *testing.T) {
|
|||
|
||||
var p PostArgs
|
||||
p.TTL = 1
|
||||
p.KeyName = keyname
|
||||
p.KeyName = keyID
|
||||
p.From = f.From
|
||||
p.Padding = []byte("test string")
|
||||
p.Payload = []byte("extended test string")
|
||||
|
|
@ -474,8 +490,7 @@ func TestIntegrationSymWithFilter(t *testing.T) {
|
|||
api.Start()
|
||||
defer api.Stop()
|
||||
|
||||
keyname := "schluessel"
|
||||
err := api.GenerateSymKey(keyname)
|
||||
keyID, err := api.GenerateSymKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to GenerateSymKey: %s.", err)
|
||||
}
|
||||
|
|
@ -500,7 +515,7 @@ func TestIntegrationSymWithFilter(t *testing.T) {
|
|||
topics[0] = TopicType{0x00, 0x7f, 0x80, 0xff}
|
||||
topics[1] = TopicType{0xf2, 0x6e, 0x77, 0x79}
|
||||
var f WhisperFilterArgs
|
||||
f.KeyName = keyname
|
||||
f.KeyName = keyID
|
||||
f.Topics = topics[:]
|
||||
f.PoW = 0.324
|
||||
f.From = sig
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ const (
|
|||
aesKeyLength = 32
|
||||
saltLength = 12
|
||||
AESNonceMaxLength = 12
|
||||
keyIdSize = 32
|
||||
|
||||
DefaultMaxMessageLength = 1024 * 1024
|
||||
DefaultMinimumPoW = 10.0 // todo: review after testing.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package whisperv5
|
|||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
crand "crypto/rand"
|
||||
"fmt"
|
||||
"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) {
|
||||
if watcher.Messages == nil {
|
||||
watcher.Messages = make(map[common.Hash]*ReceivedMessage)
|
||||
}
|
||||
|
||||
id, err := GenerateRandomID()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fs.mutex.Lock()
|
||||
defer fs.mutex.Unlock()
|
||||
|
||||
id, err := fs.generateRandomID()
|
||||
if err == nil {
|
||||
fs.watchers[id] = watcher
|
||||
if fs.watchers[id] != nil {
|
||||
return "", fmt.Errorf("failed to generate unique ID")
|
||||
}
|
||||
|
||||
fs.watchers[id] = watcher
|
||||
return id, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ func TestInstallFilters(t *testing.T) {
|
|||
t.Fatalf("seed %d: failed to install filter: %s", seed, err)
|
||||
}
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ type Whisper struct {
|
|||
filters *Filters
|
||||
|
||||
privateKeys map[string]*ecdsa.PrivateKey
|
||||
//identities map[string]*ecdsa.PrivateKey
|
||||
symKeys map[string][]byte
|
||||
keyMu sync.RWMutex
|
||||
|
||||
|
|
@ -76,6 +77,7 @@ type Whisper struct {
|
|||
func New() *Whisper {
|
||||
whisper := &Whisper{
|
||||
privateKeys: make(map[string]*ecdsa.PrivateKey),
|
||||
//identities: make(map[string]*ecdsa.PrivateKey),
|
||||
symKeys: make(map[string][]byte),
|
||||
envelopes: make(map[common.Hash]*Envelope),
|
||||
expirations: make(map[uint32]*set.SetNonTS),
|
||||
|
|
@ -231,72 +233,108 @@ func (w *Whisper) GetIdentity(pubKey string) *ecdsa.PrivateKey {
|
|||
return w.privateKeys[pubKey]
|
||||
}
|
||||
|
||||
func (w *Whisper) GenerateSymKey(name string) error {
|
||||
func (w *Whisper) GenerateSymKey() (string, error) {
|
||||
const size = aesKeyLength * 2
|
||||
buf := make([]byte, size)
|
||||
_, err := crand.Read(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
} 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]
|
||||
salt := buf[aesKeyLength:]
|
||||
derived, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
} else if !validateSymmetricKey(derived) {
|
||||
return fmt.Errorf("failed to derive valid key")
|
||||
return "", fmt.Errorf("failed to derive valid key")
|
||||
}
|
||||
|
||||
w.keyMu.Lock()
|
||||
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)
|
||||
id, err := GenerateRandomID()
|
||||
if err != nil {
|
||||
return err
|
||||
return "", fmt.Errorf("Failed to generate ID: %s", err)
|
||||
}
|
||||
|
||||
w.keyMu.Lock()
|
||||
defer w.keyMu.Unlock()
|
||||
|
||||
// double check is necessary, because deriveKeyMaterial() is slow
|
||||
if w.symKeys[name] != nil {
|
||||
return fmt.Errorf("Key with name [%s] already exists", name)
|
||||
if w.symKeys[id] != nil {
|
||||
return "", fmt.Errorf("Failed to generate unique ID")
|
||||
}
|
||||
w.symKeys[name] = derived
|
||||
return nil
|
||||
w.symKeys[id] = derived
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (w *Whisper) HasSymKey(name string) bool {
|
||||
w.keyMu.RLock()
|
||||
defer w.keyMu.RUnlock()
|
||||
return w.symKeys[name] != nil
|
||||
func (w *Whisper) AddSymKeyDirect(key []byte) (string, error) {
|
||||
if len(key) != aesKeyLength {
|
||||
return "", fmt.Errorf("Wrong key size: %d", len(key))
|
||||
}
|
||||
|
||||
id, err := GenerateRandomID()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to generate ID: %s", err)
|
||||
}
|
||||
|
||||
func (w *Whisper) DeleteSymKey(name string) {
|
||||
w.keyMu.Lock()
|
||||
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()
|
||||
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
|
||||
|
|
@ -709,3 +747,16 @@ func deriveKeyMaterial(key []byte, version uint64) (derivedKey []byte, err error
|
|||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,9 +61,12 @@ func TestWhisperBasic(t *testing.T) {
|
|||
if exist {
|
||||
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 {
|
||||
t.Fatalf("failed GetSymKey.")
|
||||
t.Fatalf("failed GetSymKey: false positive.")
|
||||
}
|
||||
mail := w.Envelopes()
|
||||
if len(mail) != 0 {
|
||||
|
|
@ -79,7 +82,7 @@ func TestWhisperBasic(t *testing.T) {
|
|||
if _, err := deriveKeyMaterial(peerID, ver); err != unknownVersionError(ver) {
|
||||
t.Fatalf("failed deriveKeyMaterial with param = %v: %s.", peerID, err)
|
||||
}
|
||||
derived, err := deriveKeyMaterial(peerID, 0)
|
||||
derived, err = deriveKeyMaterial(peerID, 0)
|
||||
if err != nil {
|
||||
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) {
|
||||
InitSingleTest()
|
||||
|
||||
var err error
|
||||
var k1, k2 []byte
|
||||
w := New()
|
||||
id1 := string("arbitrary-string-1")
|
||||
id2 := string("arbitrary-string-2")
|
||||
|
||||
err := w.GenerateSymKey(id1)
|
||||
id1, err = w.GenerateSymKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed GenerateSymKey with seed %d: %s.", seed, err)
|
||||
}
|
||||
|
||||
k1 = w.GetSymKey(id1)
|
||||
k2 = w.GetSymKey(id2)
|
||||
k1, err = w.GetSymKey(id1)
|
||||
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) {
|
||||
t.Fatalf("failed HasSymKey(id1).")
|
||||
}
|
||||
if w.HasSymKey(id2) {
|
||||
t.Fatalf("failed HasSymKey(id2).")
|
||||
t.Fatalf("failed HasSymKey(id2): false positive.")
|
||||
}
|
||||
if k1 == nil {
|
||||
t.Fatalf("first key does not exist.")
|
||||
|
|
@ -210,38 +220,49 @@ func TestWhisperSymKeyManagement(t *testing.T) {
|
|||
t.Fatalf("second key still exist.")
|
||||
}
|
||||
|
||||
// add existing id, nothing should change
|
||||
randomKey := make([]byte, 16)
|
||||
randomKey := make([]byte, aesKeyLength)
|
||||
randomize(randomKey)
|
||||
err = w.AddSymKey(id1, randomKey)
|
||||
if err == nil {
|
||||
t.Fatalf("failed AddSymKey with seed %d.", seed)
|
||||
id1, err = w.AddSymKeyDirect(randomKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed AddSymKey with seed %d: %s.", seed, err)
|
||||
}
|
||||
|
||||
k1 = w.GetSymKey(id1)
|
||||
k2 = w.GetSymKey(id2)
|
||||
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): false positive.")
|
||||
}
|
||||
if !w.HasSymKey(id1) {
|
||||
t.Fatalf("failed w.HasSymKey(id1).")
|
||||
}
|
||||
if w.HasSymKey(id2) {
|
||||
t.Fatalf("failed w.HasSymKey(id2).")
|
||||
t.Fatalf("failed w.HasSymKey(id2): false positive.")
|
||||
}
|
||||
if k1 == nil {
|
||||
t.Fatalf("first key does not exist.")
|
||||
}
|
||||
if bytes.Equal(k1, randomKey) {
|
||||
t.Fatalf("k1 == randomKey.")
|
||||
if !bytes.Equal(k1, randomKey) {
|
||||
t.Fatalf("k1 != randomKey.")
|
||||
}
|
||||
if k2 != nil {
|
||||
t.Fatalf("second key already exist.")
|
||||
}
|
||||
|
||||
err = w.AddSymKey(id2, randomKey) // add non-existing (yet)
|
||||
id2, err = w.AddSymKeyDirect(randomKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed AddSymKey(id2) with seed %d: %s.", seed, err)
|
||||
}
|
||||
k1 = w.GetSymKey(id1)
|
||||
k2 = w.GetSymKey(id2)
|
||||
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.")
|
||||
}
|
||||
|
|
@ -254,11 +275,11 @@ func TestWhisperSymKeyManagement(t *testing.T) {
|
|||
if k2 == nil {
|
||||
t.Fatalf("k2 does not exist.")
|
||||
}
|
||||
if bytes.Equal(k1, k2) {
|
||||
t.Fatalf("k1 == k2.")
|
||||
if !bytes.Equal(k1, k2) {
|
||||
t.Fatalf("k1 != k2.")
|
||||
}
|
||||
if bytes.Equal(k1, randomKey) {
|
||||
t.Fatalf("k1 == randomKey.")
|
||||
if !bytes.Equal(k1, randomKey) {
|
||||
t.Fatalf("k1 != randomKey.")
|
||||
}
|
||||
if len(k1) != aesKeyLength {
|
||||
t.Fatalf("wrong length of k1.")
|
||||
|
|
@ -268,8 +289,17 @@ func TestWhisperSymKeyManagement(t *testing.T) {
|
|||
}
|
||||
|
||||
w.DeleteSymKey(id1)
|
||||
k1 = w.GetSymKey(id1)
|
||||
k2 = w.GetSymKey(id2)
|
||||
k1, err = w.GetSymKey(id1)
|
||||
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) {
|
||||
t.Fatalf("failed to delete first key: still exist.")
|
||||
}
|
||||
|
|
@ -285,8 +315,17 @@ func TestWhisperSymKeyManagement(t *testing.T) {
|
|||
|
||||
w.DeleteSymKey(id1)
|
||||
w.DeleteSymKey(id2)
|
||||
k1 = w.GetSymKey(id1)
|
||||
k2 = w.GetSymKey(id2)
|
||||
k1, err = w.GetSymKey(id1)
|
||||
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) {
|
||||
t.Fatalf("failed to delete second key: first key exist.")
|
||||
}
|
||||
|
|
@ -299,6 +338,55 @@ func TestWhisperSymKeyManagement(t *testing.T) {
|
|||
if k2 != 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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue