status-go/vendor/github.com/ethereum/go-ethereum/whisper/notifications/utils.go

85 lines
2.4 KiB
Go

package notifications
import (
"crypto/sha512"
"errors"
"crypto/sha256"
crand "crypto/rand"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
"golang.org/x/crypto/pbkdf2"
)
// makeSessionKey returns pseudo-random symmetric key, which is used as
// session key between notification client and server
func makeSessionKey() ([]byte, error) {
// generate random key
const keyLen = 32
buf := make([]byte, keyLen)
_, err := crand.Read(buf)
if err != nil {
return nil, err
} else if !validateSymmetricKey(buf) {
return nil, errors.New("error in GenerateSymKey: crypto/rand failed to generate random data")
}
key := buf[:keyLen]
derived, err := deriveKeyMaterial(key, whisper.EnvelopeVersion)
if err != nil {
return nil, err
} else if !validateSymmetricKey(derived) {
return nil, errors.New("failed to derive valid key")
}
return derived, nil
}
// validateSymmetricKey returns false if the key contains all zeros
func validateSymmetricKey(k []byte) bool {
return len(k) > 0 && !containsOnlyZeros(k)
}
// containsOnlyZeros checks if data is empty or not
func containsOnlyZeros(data []byte) bool {
for _, b := range data {
if b != 0 {
return false
}
}
return true
}
// deriveKeyMaterial derives symmetric key material from the key or password./~~~
// pbkdf2 is used for security, in case people use password instead of randomly generated keys.
func deriveKeyMaterial(key []byte, version uint64) (derivedKey []byte, err error) {
if version == 0 {
// kdf should run no less than 0.1 seconds on average compute,
// because it's a once in a session experience
derivedKey := pbkdf2.Key(key, nil, 65356, 32, sha256.New)
return derivedKey, nil
} else {
return nil, errors.New("unknown version")
}
}
// MakeTopic returns Whisper topic *as bytes array* by generating cryptographic key from the provided password
func MakeTopicAsBytes(password []byte) ([]byte) {
topic := make([]byte, int(whisper.TopicLength))
x := pbkdf2.Key(password, password, 8196, 128, sha512.New)
for i := 0; i < len(x); i++ {
topic[i%whisper.TopicLength] ^= x[i]
}
return topic
}
// MakeTopic returns Whisper topic by generating cryptographic key from the provided password
func MakeTopic(password []byte) (topic whisper.TopicType) {
x := pbkdf2.Key(password, password, 8196, 128, sha512.New)
for i := 0; i < len(x); i++ {
topic[i%whisper.TopicLength] ^= x[i]
}
return
}