github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/whisper/whisperv5/whisper.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package whisperv5
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/ecdsa"
    22  	crand "crypto/rand"
    23  	"crypto/sha256"
    24  	"fmt"
    25  	"runtime"
    26  	"sync"
    27  	"time"
    28  
    29  	"github.com/atheioschain/go-atheios/common"
    30  	"github.com/atheioschain/go-atheios/crypto"
    31  	"github.com/atheioschain/go-atheios/logger"
    32  	"github.com/atheioschain/go-atheios/logger/glog"
    33  	"github.com/atheioschain/go-atheios/p2p"
    34  	"golang.org/x/crypto/pbkdf2"
    35  	set "gopkg.in/fatih/set.v0"
    36  )
    37  
    38  // Whisper represents a dark communication interface through the Ethereum
    39  // network, using its very own P2P communication layer.
    40  type Whisper struct {
    41  	protocol p2p.Protocol
    42  	filters  *Filters
    43  
    44  	privateKeys map[string]*ecdsa.PrivateKey
    45  	symKeys     map[string][]byte
    46  	keyMu       sync.RWMutex
    47  
    48  	envelopes   map[common.Hash]*Envelope        // Pool of envelopes currently tracked by this node
    49  	messages    map[common.Hash]*ReceivedMessage // Pool of successfully decrypted messages, which are not expired yet
    50  	expirations map[uint32]*set.SetNonTS         // Message expiration pool
    51  	poolMu      sync.RWMutex                     // Mutex to sync the message and expiration pools
    52  
    53  	peers  map[*Peer]struct{} // Set of currently active peers
    54  	peerMu sync.RWMutex       // Mutex to sync the active peer set
    55  
    56  	mailServer MailServer
    57  
    58  	messageQueue chan *Envelope
    59  	p2pMsgQueue  chan *Envelope
    60  	quit         chan struct{}
    61  
    62  	overflow bool
    63  	test     bool
    64  }
    65  
    66  // New creates a Whisper client ready to communicate through the Ethereum P2P network.
    67  // Param s should be passed if you want to implement mail server, otherwise nil.
    68  func NewWhisper(server MailServer) *Whisper {
    69  	whisper := &Whisper{
    70  		privateKeys:  make(map[string]*ecdsa.PrivateKey),
    71  		symKeys:      make(map[string][]byte),
    72  		envelopes:    make(map[common.Hash]*Envelope),
    73  		messages:     make(map[common.Hash]*ReceivedMessage),
    74  		expirations:  make(map[uint32]*set.SetNonTS),
    75  		peers:        make(map[*Peer]struct{}),
    76  		mailServer:   server,
    77  		messageQueue: make(chan *Envelope, messageQueueLimit),
    78  		p2pMsgQueue:  make(chan *Envelope, messageQueueLimit),
    79  		quit:         make(chan struct{}),
    80  	}
    81  	whisper.filters = NewFilters(whisper)
    82  
    83  	// p2p whisper sub protocol handler
    84  	whisper.protocol = p2p.Protocol{
    85  		Name:    ProtocolName,
    86  		Version: uint(ProtocolVersion),
    87  		Length:  NumberOfMessageCodes,
    88  		Run:     whisper.HandlePeer,
    89  	}
    90  
    91  	return whisper
    92  }
    93  
    94  // Protocols returns the whisper sub-protocols ran by this particular client.
    95  func (w *Whisper) Protocols() []p2p.Protocol {
    96  	return []p2p.Protocol{w.protocol}
    97  }
    98  
    99  // Version returns the whisper sub-protocols version number.
   100  func (w *Whisper) Version() uint {
   101  	return w.protocol.Version
   102  }
   103  
   104  func (w *Whisper) getPeer(peerID []byte) (*Peer, error) {
   105  	w.peerMu.Lock()
   106  	defer w.peerMu.Unlock()
   107  	for p := range w.peers {
   108  		id := p.peer.ID()
   109  		if bytes.Equal(peerID, id[:]) {
   110  			return p, nil
   111  		}
   112  	}
   113  	return nil, fmt.Errorf("Could not find peer with ID: %x", peerID)
   114  }
   115  
   116  // MarkPeerTrusted marks specific peer trusted, which will allow it
   117  // to send historic (expired) messages.
   118  func (w *Whisper) MarkPeerTrusted(peerID []byte) error {
   119  	p, err := w.getPeer(peerID)
   120  	if err != nil {
   121  		return err
   122  	}
   123  	p.trusted = true
   124  	return nil
   125  }
   126  
   127  func (w *Whisper) RequestHistoricMessages(peerID []byte, envelope *Envelope) error {
   128  	p, err := w.getPeer(peerID)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	p.trusted = true
   133  	return p2p.Send(p.ws, p2pRequestCode, envelope)
   134  }
   135  
   136  func (w *Whisper) SendP2PMessage(peerID []byte, envelope *Envelope) error {
   137  	p, err := w.getPeer(peerID)
   138  	if err != nil {
   139  		return err
   140  	}
   141  	return p2p.Send(p.ws, p2pCode, envelope)
   142  }
   143  
   144  func (w *Whisper) SendP2PDirect(peer *Peer, envelope *Envelope) error {
   145  	return p2p.Send(peer.ws, p2pCode, envelope)
   146  }
   147  
   148  // NewIdentity generates a new cryptographic identity for the client, and injects
   149  // it into the known identities for message decryption.
   150  func (w *Whisper) NewIdentity() *ecdsa.PrivateKey {
   151  	key, err := crypto.GenerateKey()
   152  	if err != nil || !validatePrivateKey(key) {
   153  		key, err = crypto.GenerateKey() // retry once
   154  	}
   155  	if err != nil {
   156  		panic(err)
   157  	}
   158  	if !validatePrivateKey(key) {
   159  		panic("Failed to generate valid key")
   160  	}
   161  	w.keyMu.Lock()
   162  	defer w.keyMu.Unlock()
   163  	w.privateKeys[common.ToHex(crypto.FromECDSAPub(&key.PublicKey))] = key
   164  	return key
   165  }
   166  
   167  // DeleteIdentity deletes the specified key if it exists.
   168  func (w *Whisper) DeleteIdentity(key string) {
   169  	w.keyMu.Lock()
   170  	defer w.keyMu.Unlock()
   171  	delete(w.privateKeys, key)
   172  }
   173  
   174  // HasIdentity checks if the the whisper node is configured with the private key
   175  // of the specified public pair.
   176  func (w *Whisper) HasIdentity(pubKey string) bool {
   177  	w.keyMu.RLock()
   178  	defer w.keyMu.RUnlock()
   179  	return w.privateKeys[pubKey] != nil
   180  }
   181  
   182  // GetIdentity retrieves the private key of the specified public identity.
   183  func (w *Whisper) GetIdentity(pubKey string) *ecdsa.PrivateKey {
   184  	w.keyMu.RLock()
   185  	defer w.keyMu.RUnlock()
   186  	return w.privateKeys[pubKey]
   187  }
   188  
   189  func (w *Whisper) GenerateSymKey(name string) error {
   190  	const size = aesKeyLength * 2
   191  	buf := make([]byte, size)
   192  	_, err := crand.Read(buf)
   193  	if err != nil {
   194  		return err
   195  	} else if !validateSymmetricKey(buf) {
   196  		return fmt.Errorf("error in GenerateSymKey: crypto/rand failed to generate random data")
   197  	}
   198  
   199  	key := buf[:aesKeyLength]
   200  	salt := buf[aesKeyLength:]
   201  	derived, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
   202  	if err != nil {
   203  		return err
   204  	} else if !validateSymmetricKey(derived) {
   205  		return fmt.Errorf("failed to derive valid key")
   206  	}
   207  
   208  	w.keyMu.Lock()
   209  	defer w.keyMu.Unlock()
   210  
   211  	if w.symKeys[name] != nil {
   212  		return fmt.Errorf("Key with name [%s] already exists", name)
   213  	}
   214  	w.symKeys[name] = derived
   215  	return nil
   216  }
   217  
   218  func (w *Whisper) AddSymKey(name string, key []byte) error {
   219  	if w.HasSymKey(name) {
   220  		return fmt.Errorf("Key with name [%s] already exists", name)
   221  	}
   222  
   223  	derived, err := deriveKeyMaterial(key, EnvelopeVersion)
   224  	if err != nil {
   225  		return err
   226  	}
   227  
   228  	w.keyMu.Lock()
   229  	defer w.keyMu.Unlock()
   230  
   231  	// double check is necessary, because deriveKeyMaterial() is slow
   232  	if w.symKeys[name] != nil {
   233  		return fmt.Errorf("Key with name [%s] already exists", name)
   234  	}
   235  	w.symKeys[name] = derived
   236  	return nil
   237  }
   238  
   239  func (w *Whisper) HasSymKey(name string) bool {
   240  	w.keyMu.RLock()
   241  	defer w.keyMu.RUnlock()
   242  	return w.symKeys[name] != nil
   243  }
   244  
   245  func (w *Whisper) DeleteSymKey(name string) {
   246  	w.keyMu.Lock()
   247  	defer w.keyMu.Unlock()
   248  	delete(w.symKeys, name)
   249  }
   250  
   251  func (w *Whisper) GetSymKey(name string) []byte {
   252  	w.keyMu.RLock()
   253  	defer w.keyMu.RUnlock()
   254  	return w.symKeys[name]
   255  }
   256  
   257  // Watch installs a new message handler to run in case a matching packet arrives
   258  // from the whisper network.
   259  func (w *Whisper) Watch(f *Filter) uint32 {
   260  	return w.filters.Install(f)
   261  }
   262  
   263  func (w *Whisper) GetFilter(id uint32) *Filter {
   264  	return w.filters.Get(id)
   265  }
   266  
   267  // Unwatch removes an installed message handler.
   268  func (w *Whisper) Unwatch(id uint32) {
   269  	w.filters.Uninstall(id)
   270  }
   271  
   272  // Send injects a message into the whisper send queue, to be distributed in the
   273  // network in the coming cycles.
   274  func (w *Whisper) Send(envelope *Envelope) error {
   275  	return w.add(envelope)
   276  }
   277  
   278  // Start implements node.Service, starting the background data propagation thread
   279  // of the Whisper protocol.
   280  func (w *Whisper) Start(*p2p.Server) error {
   281  	glog.V(logger.Info).Infoln("Whisper started")
   282  	go w.update()
   283  
   284  	numCPU := runtime.NumCPU()
   285  	for i := 0; i < numCPU; i++ {
   286  		go w.processQueue()
   287  	}
   288  
   289  	return nil
   290  }
   291  
   292  // Stop implements node.Service, stopping the background data propagation thread
   293  // of the Whisper protocol.
   294  func (w *Whisper) Stop() error {
   295  	close(w.quit)
   296  	glog.V(logger.Info).Infoln("Whisper stopped")
   297  	return nil
   298  }
   299  
   300  // handlePeer is called by the underlying P2P layer when the whisper sub-protocol
   301  // connection is negotiated.
   302  func (wh *Whisper) HandlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error {
   303  	// Create the new peer and start tracking it
   304  	whisperPeer := newPeer(wh, peer, rw)
   305  
   306  	wh.peerMu.Lock()
   307  	wh.peers[whisperPeer] = struct{}{}
   308  	wh.peerMu.Unlock()
   309  
   310  	defer func() {
   311  		wh.peerMu.Lock()
   312  		delete(wh.peers, whisperPeer)
   313  		wh.peerMu.Unlock()
   314  	}()
   315  
   316  	// Run the peer handshake and state updates
   317  	if err := whisperPeer.handshake(); err != nil {
   318  		return err
   319  	}
   320  	whisperPeer.start()
   321  	defer whisperPeer.stop()
   322  
   323  	return wh.runMessageLoop(whisperPeer, rw)
   324  }
   325  
   326  // runMessageLoop reads and processes inbound messages directly to merge into client-global state.
   327  func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
   328  	for {
   329  		// fetch the next packet
   330  		packet, err := rw.ReadMsg()
   331  		if err != nil {
   332  			return err
   333  		}
   334  
   335  		switch packet.Code {
   336  		case statusCode:
   337  			// this should not happen, but no need to panic; just ignore this message.
   338  			glog.V(logger.Warn).Infof("%v: unxepected status message received", p.peer)
   339  		case messagesCode:
   340  			// decode the contained envelopes
   341  			var envelopes []*Envelope
   342  			if err := packet.Decode(&envelopes); err != nil {
   343  				glog.V(logger.Warn).Infof("%v: failed to decode envelope: [%v], peer will be disconnected", p.peer, err)
   344  				return fmt.Errorf("garbage received")
   345  			}
   346  			// inject all envelopes into the internal pool
   347  			for _, envelope := range envelopes {
   348  				if err := wh.add(envelope); err != nil {
   349  					glog.V(logger.Warn).Infof("%v: bad envelope received: [%v], peer will be disconnected", p.peer, err)
   350  					return fmt.Errorf("invalid envelope")
   351  				}
   352  				p.mark(envelope)
   353  			}
   354  		case p2pCode:
   355  			// peer-to-peer message, sent directly to peer bypassing PoW checks, etc.
   356  			// this message is not supposed to be forwarded to other peers, and
   357  			// therefore might not satisfy the PoW, expiry and other requirements.
   358  			// these messages are only accepted from the trusted peer.
   359  			if p.trusted {
   360  				var envelope Envelope
   361  				if err := packet.Decode(&envelope); err != nil {
   362  					glog.V(logger.Warn).Infof("%v: failed to decode direct message: [%v], peer will be disconnected", p.peer, err)
   363  					return fmt.Errorf("garbage received (directMessage)")
   364  				}
   365  				wh.postEvent(&envelope, true)
   366  			}
   367  		case p2pRequestCode:
   368  			// Must be processed if mail server is implemented. Otherwise ignore.
   369  			if wh.mailServer != nil {
   370  				var request Envelope
   371  				if err := packet.Decode(&request); err != nil {
   372  					glog.V(logger.Warn).Infof("%v: failed to decode p2p request message: [%v], peer will be disconnected", p.peer, err)
   373  					return fmt.Errorf("garbage received (p2p request)")
   374  				}
   375  				wh.mailServer.DeliverMail(p, &request)
   376  			}
   377  		default:
   378  			// New message types might be implemented in the future versions of Whisper.
   379  			// For forward compatibility, just ignore.
   380  		}
   381  
   382  		packet.Discard()
   383  	}
   384  }
   385  
   386  // add inserts a new envelope into the message pool to be distributed within the
   387  // whisper network. It also inserts the envelope into the expiration pool at the
   388  // appropriate time-stamp. In case of error, connection should be dropped.
   389  func (wh *Whisper) add(envelope *Envelope) error {
   390  	now := uint32(time.Now().Unix())
   391  	sent := envelope.Expiry - envelope.TTL
   392  
   393  	if sent > now {
   394  		if sent-SynchAllowance > now {
   395  			return fmt.Errorf("envelope created in the future [%x]", envelope.Hash())
   396  		} else {
   397  			// recalculate PoW, adjusted for the time difference, plus one second for latency
   398  			envelope.calculatePoW(sent - now + 1)
   399  		}
   400  	}
   401  
   402  	if envelope.Expiry < now {
   403  		if envelope.Expiry+SynchAllowance*2 < now {
   404  			return fmt.Errorf("very old message")
   405  		} else {
   406  			glog.V(logger.Debug).Infof("expired envelope dropped [%x]", envelope.Hash())
   407  			return nil // drop envelope without error
   408  		}
   409  	}
   410  
   411  	if len(envelope.Data) > MaxMessageLength {
   412  		return fmt.Errorf("huge messages are not allowed [%x]", envelope.Hash())
   413  	}
   414  
   415  	if len(envelope.Version) > 4 {
   416  		return fmt.Errorf("oversized version [%x]", envelope.Hash())
   417  	}
   418  
   419  	if len(envelope.AESNonce) > AESNonceMaxLength {
   420  		// the standard AES GSM nonce size is 12,
   421  		// but const gcmStandardNonceSize cannot be accessed directly
   422  		return fmt.Errorf("oversized AESNonce [%x]", envelope.Hash())
   423  	}
   424  
   425  	if len(envelope.Salt) > saltLength {
   426  		return fmt.Errorf("oversized salt [%x]", envelope.Hash())
   427  	}
   428  
   429  	if envelope.PoW() < MinimumPoW && !wh.test {
   430  		glog.V(logger.Debug).Infof("envelope with low PoW dropped: %f [%x]", envelope.PoW(), envelope.Hash())
   431  		return nil // drop envelope without error
   432  	}
   433  
   434  	hash := envelope.Hash()
   435  
   436  	wh.poolMu.Lock()
   437  	_, alreadyCached := wh.envelopes[hash]
   438  	if !alreadyCached {
   439  		wh.envelopes[hash] = envelope
   440  		if wh.expirations[envelope.Expiry] == nil {
   441  			wh.expirations[envelope.Expiry] = set.NewNonTS()
   442  		}
   443  		if !wh.expirations[envelope.Expiry].Has(hash) {
   444  			wh.expirations[envelope.Expiry].Add(hash)
   445  		}
   446  	}
   447  	wh.poolMu.Unlock()
   448  
   449  	if alreadyCached {
   450  		glog.V(logger.Detail).Infof("whisper envelope already cached [%x]\n", envelope.Hash())
   451  	} else {
   452  		glog.V(logger.Detail).Infof("cached whisper envelope [%x]: %v\n", envelope.Hash(), envelope)
   453  		wh.postEvent(envelope, false) // notify the local node about the new message
   454  		if wh.mailServer != nil {
   455  			wh.mailServer.Archive(envelope)
   456  		}
   457  	}
   458  	return nil
   459  }
   460  
   461  // postEvent queues the message for further processing.
   462  func (w *Whisper) postEvent(envelope *Envelope, isP2P bool) {
   463  	// if the version of incoming message is higher than
   464  	// currently supported version, we can not decrypt it,
   465  	// and therefore just ignore this message
   466  	if envelope.Ver() <= EnvelopeVersion {
   467  		if isP2P {
   468  			w.p2pMsgQueue <- envelope
   469  		} else {
   470  			w.checkOverflow()
   471  			w.messageQueue <- envelope
   472  		}
   473  	}
   474  }
   475  
   476  // checkOverflow checks if message queue overflow occurs and reports it if necessary.
   477  func (w *Whisper) checkOverflow() {
   478  	queueSize := len(w.messageQueue)
   479  
   480  	if queueSize == messageQueueLimit {
   481  		if !w.overflow {
   482  			w.overflow = true
   483  			glog.V(logger.Warn).Infoln("message queue overflow")
   484  		}
   485  	} else if queueSize <= messageQueueLimit/2 {
   486  		if w.overflow {
   487  			w.overflow = false
   488  		}
   489  	}
   490  }
   491  
   492  // processQueue delivers the messages to the watchers during the lifetime of the whisper node.
   493  func (w *Whisper) processQueue() {
   494  	var e *Envelope
   495  	for {
   496  		select {
   497  		case <-w.quit:
   498  			return
   499  
   500  		case e = <-w.messageQueue:
   501  			w.filters.NotifyWatchers(e, false)
   502  
   503  		case e = <-w.p2pMsgQueue:
   504  			w.filters.NotifyWatchers(e, true)
   505  		}
   506  	}
   507  }
   508  
   509  // update loops until the lifetime of the whisper node, updating its internal
   510  // state by expiring stale messages from the pool.
   511  func (w *Whisper) update() {
   512  	// Start a ticker to check for expirations
   513  	expire := time.NewTicker(expirationCycle)
   514  
   515  	// Repeat updates until termination is requested
   516  	for {
   517  		select {
   518  		case <-expire.C:
   519  			w.expire()
   520  
   521  		case <-w.quit:
   522  			return
   523  		}
   524  	}
   525  }
   526  
   527  // expire iterates over all the expiration timestamps, removing all stale
   528  // messages from the pools.
   529  func (w *Whisper) expire() {
   530  	w.poolMu.Lock()
   531  	defer w.poolMu.Unlock()
   532  
   533  	now := uint32(time.Now().Unix())
   534  	for then, hashSet := range w.expirations {
   535  		// Short circuit if a future time
   536  		if then > now {
   537  			continue
   538  		}
   539  		// Dump all expired messages and remove timestamp
   540  		hashSet.Each(func(v interface{}) bool {
   541  			delete(w.envelopes, v.(common.Hash))
   542  			delete(w.messages, v.(common.Hash))
   543  			return true
   544  		})
   545  		w.expirations[then].Clear()
   546  	}
   547  }
   548  
   549  // envelopes retrieves all the messages currently pooled by the node.
   550  func (w *Whisper) Envelopes() []*Envelope {
   551  	w.poolMu.RLock()
   552  	defer w.poolMu.RUnlock()
   553  
   554  	all := make([]*Envelope, 0, len(w.envelopes))
   555  	for _, envelope := range w.envelopes {
   556  		all = append(all, envelope)
   557  	}
   558  	return all
   559  }
   560  
   561  // Messages retrieves all the decrypted messages matching a filter id.
   562  func (w *Whisper) Messages(id uint32) []*ReceivedMessage {
   563  	result := make([]*ReceivedMessage, 0)
   564  	w.poolMu.RLock()
   565  	defer w.poolMu.RUnlock()
   566  
   567  	if filter := w.filters.Get(id); filter != nil {
   568  		for _, msg := range w.messages {
   569  			if filter.MatchMessage(msg) {
   570  				result = append(result, msg)
   571  			}
   572  		}
   573  	}
   574  	return result
   575  }
   576  
   577  func (w *Whisper) addDecryptedMessage(msg *ReceivedMessage) {
   578  	w.poolMu.Lock()
   579  	defer w.poolMu.Unlock()
   580  
   581  	w.messages[msg.EnvelopeHash] = msg
   582  }
   583  
   584  func ValidatePublicKey(k *ecdsa.PublicKey) bool {
   585  	return k != nil && k.X != nil && k.Y != nil && k.X.Sign() != 0 && k.Y.Sign() != 0
   586  }
   587  
   588  func validatePrivateKey(k *ecdsa.PrivateKey) bool {
   589  	if k == nil || k.D == nil || k.D.Sign() == 0 {
   590  		return false
   591  	}
   592  	return ValidatePublicKey(&k.PublicKey)
   593  }
   594  
   595  // validateSymmetricKey returns false if the key contains all zeros
   596  func validateSymmetricKey(k []byte) bool {
   597  	return len(k) > 0 && !containsOnlyZeros(k)
   598  }
   599  
   600  func containsOnlyZeros(data []byte) bool {
   601  	for _, b := range data {
   602  		if b != 0 {
   603  			return false
   604  		}
   605  	}
   606  	return true
   607  }
   608  
   609  func bytesToIntLittleEndian(b []byte) (res uint64) {
   610  	mul := uint64(1)
   611  	for i := 0; i < len(b); i++ {
   612  		res += uint64(b[i]) * mul
   613  		mul *= 256
   614  	}
   615  	return res
   616  }
   617  
   618  func BytesToIntBigEndian(b []byte) (res uint64) {
   619  	for i := 0; i < len(b); i++ {
   620  		res *= 256
   621  		res += uint64(b[i])
   622  	}
   623  	return res
   624  }
   625  
   626  // DeriveSymmetricKey derives symmetric key material from the key or password.
   627  // pbkdf2 is used for security, in case people use password instead of randomly generated keys.
   628  func deriveKeyMaterial(key []byte, version uint64) (derivedKey []byte, err error) {
   629  	if version == 0 {
   630  		// kdf should run no less than 0.1 seconds on average compute,
   631  		// because it's a once in a session experience
   632  		derivedKey := pbkdf2.Key(key, nil, 65356, aesKeyLength, sha256.New)
   633  		return derivedKey, nil
   634  	} else {
   635  		return nil, unknownVersionError(version)
   636  	}
   637  }