whisper: message format refactoring (#14335)
* whisper: salt removed from AES encryption * whisper: padding format updated * whisper: padding test added * whisper: padding refactored, tests fixed * whisper: padding test updated * whisper: wnode bugfix * whisper: send/receive protocol updated * whisper: minor update * whisper: bugfix in test * whisper: updated parameter names and comments * whisper: functions renamed * whisper: minor refactoring
This commit is contained in:
parent
8dce4c283d
commit
95f0bd0acf
@ -65,7 +65,7 @@ var (
|
|||||||
pub *ecdsa.PublicKey
|
pub *ecdsa.PublicKey
|
||||||
asymKey *ecdsa.PrivateKey
|
asymKey *ecdsa.PrivateKey
|
||||||
nodeid *ecdsa.PrivateKey
|
nodeid *ecdsa.PrivateKey
|
||||||
topic []byte
|
topic whisper.TopicType
|
||||||
asymKeyID string
|
asymKeyID string
|
||||||
filterID string
|
filterID string
|
||||||
symPass string
|
symPass string
|
||||||
@ -84,7 +84,7 @@ var (
|
|||||||
testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics")
|
testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics")
|
||||||
echoMode = flag.Bool("echo", false, "echo mode: prints some arguments for diagnostics")
|
echoMode = flag.Bool("echo", false, "echo mode: prints some arguments for diagnostics")
|
||||||
|
|
||||||
argVerbosity = flag.Int("verbosity", int(log.LvlWarn), "log verbosity level")
|
argVerbosity = flag.Int("verbosity", int(log.LvlError), "log verbosity level")
|
||||||
argTTL = flag.Uint("ttl", 30, "time-to-live for messages in seconds")
|
argTTL = flag.Uint("ttl", 30, "time-to-live for messages in seconds")
|
||||||
argWorkTime = flag.Uint("work", 5, "work time in seconds")
|
argWorkTime = flag.Uint("work", 5, "work time in seconds")
|
||||||
argMaxSize = flag.Int("maxsize", whisper.DefaultMaxMessageLength, "max size of message")
|
argMaxSize = flag.Int("maxsize", whisper.DefaultMaxMessageLength, "max size of message")
|
||||||
@ -129,7 +129,7 @@ func processArgs() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to parse the topic: %s", err)
|
utils.Fatalf("Failed to parse the topic: %s", err)
|
||||||
}
|
}
|
||||||
topic = x
|
topic = whisper.BytesToTopic(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *asymmetricMode && len(*argPub) > 0 {
|
if *asymmetricMode && len(*argPub) > 0 {
|
||||||
@ -307,7 +307,11 @@ func configureNode() {
|
|||||||
if *asymmetricMode {
|
if *asymmetricMode {
|
||||||
if len(*argPub) == 0 {
|
if len(*argPub) == 0 {
|
||||||
s := scanLine("Please enter the peer's public key: ")
|
s := scanLine("Please enter the peer's public key: ")
|
||||||
pub = crypto.ToECDSAPub(common.FromHex(s))
|
b := common.FromHex(s)
|
||||||
|
if b == nil {
|
||||||
|
utils.Fatalf("Error: can not convert hexadecimal string")
|
||||||
|
}
|
||||||
|
pub = crypto.ToECDSAPub(b)
|
||||||
if !isKeyValid(pub) {
|
if !isKeyValid(pub) {
|
||||||
utils.Fatalf("Error: invalid public key")
|
utils.Fatalf("Error: invalid public key")
|
||||||
}
|
}
|
||||||
@ -354,7 +358,7 @@ func configureNode() {
|
|||||||
filter := whisper.Filter{
|
filter := whisper.Filter{
|
||||||
KeySym: symKey,
|
KeySym: symKey,
|
||||||
KeyAsym: asymKey,
|
KeyAsym: asymKey,
|
||||||
Topics: [][]byte{topic},
|
Topics: [][]byte{topic[:]},
|
||||||
AllowP2P: p2pAccept,
|
AllowP2P: p2pAccept,
|
||||||
}
|
}
|
||||||
filterID, err = shh.Subscribe(&filter)
|
filterID, err = shh.Subscribe(&filter)
|
||||||
@ -365,7 +369,7 @@ func configureNode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func generateTopic(password []byte) {
|
func generateTopic(password []byte) {
|
||||||
x := pbkdf2.Key(password, password, 8196, 128, sha512.New)
|
x := pbkdf2.Key(password, password, 4096, 128, sha512.New)
|
||||||
for i := 0; i < len(x); i++ {
|
for i := 0; i < len(x); i++ {
|
||||||
topic[i%whisper.TopicLength] ^= x[i]
|
topic[i%whisper.TopicLength] ^= x[i]
|
||||||
}
|
}
|
||||||
@ -485,16 +489,15 @@ func sendMsg(payload []byte) common.Hash {
|
|||||||
Dst: pub,
|
Dst: pub,
|
||||||
KeySym: symKey,
|
KeySym: symKey,
|
||||||
Payload: payload,
|
Payload: payload,
|
||||||
Topic: whisper.BytesToTopic(topic),
|
Topic: topic,
|
||||||
TTL: uint32(*argTTL),
|
TTL: uint32(*argTTL),
|
||||||
PoW: *argPoW,
|
PoW: *argPoW,
|
||||||
WorkTime: uint32(*argWorkTime),
|
WorkTime: uint32(*argWorkTime),
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := whisper.NewSentMessage(¶ms)
|
msg, err := whisper.NewSentMessage(¶ms)
|
||||||
if msg == nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to create new message (OS level error)")
|
utils.Fatalf("failed to create new message: %s", err)
|
||||||
os.Exit(0)
|
|
||||||
}
|
}
|
||||||
envelope, err := msg.Wrap(¶ms)
|
envelope, err := msg.Wrap(¶ms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -624,9 +627,9 @@ func requestExpiredMessagesLoop() {
|
|||||||
params.Src = nodeid
|
params.Src = nodeid
|
||||||
params.WorkTime = 5
|
params.WorkTime = 5
|
||||||
|
|
||||||
msg := whisper.NewSentMessage(¶ms)
|
msg, err := whisper.NewSentMessage(¶ms)
|
||||||
if msg == nil {
|
if err != nil {
|
||||||
utils.Fatalf("failed to create new message (OS level error)")
|
utils.Fatalf("failed to create new message: %s", err)
|
||||||
}
|
}
|
||||||
env, err := msg.Wrap(¶ms)
|
env, err := msg.Wrap(¶ms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,15 +58,19 @@ func TestDBKey(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func generateEnvelope(t *testing.T) *whisper.Envelope {
|
func generateEnvelope(t *testing.T) *whisper.Envelope {
|
||||||
|
h := crypto.Keccak256Hash([]byte("test sample data"))
|
||||||
params := &whisper.MessageParams{
|
params := &whisper.MessageParams{
|
||||||
KeySym: []byte("test key"),
|
KeySym: h[:],
|
||||||
Topic: whisper.TopicType{},
|
Topic: whisper.TopicType{},
|
||||||
Payload: []byte("test payload"),
|
Payload: []byte("test payload"),
|
||||||
PoW: powRequirement,
|
PoW: powRequirement,
|
||||||
WorkTime: 2,
|
WorkTime: 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := whisper.NewSentMessage(params)
|
msg, err := whisper.NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed to wrap with seed %d: %s.", seed, err)
|
||||||
@ -188,7 +192,10 @@ func createRequest(t *testing.T, p *ServerTestParams) *whisper.Envelope {
|
|||||||
Src: p.key,
|
Src: p.key,
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := whisper.NewSentMessage(params)
|
msg, err := whisper.NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed to wrap with seed %d: %s.", seed, err)
|
||||||
|
@ -214,7 +214,6 @@ func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filter := Filter{
|
filter := Filter{
|
||||||
Src: crypto.ToECDSAPub(common.FromHex(args.SignedWith)),
|
|
||||||
PoW: args.MinPoW,
|
PoW: args.MinPoW,
|
||||||
Messages: make(map[common.Hash]*ReceivedMessage),
|
Messages: make(map[common.Hash]*ReceivedMessage),
|
||||||
AllowP2P: args.AllowP2P,
|
AllowP2P: args.AllowP2P,
|
||||||
@ -233,6 +232,11 @@ func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(args.SignedWith) > 0 {
|
if len(args.SignedWith) > 0 {
|
||||||
|
sb := common.FromHex(args.SignedWith)
|
||||||
|
if sb == nil {
|
||||||
|
return "", errors.New("subscribe: SignedWith parameter is invalid")
|
||||||
|
}
|
||||||
|
filter.Src = crypto.ToECDSAPub(sb)
|
||||||
if !ValidatePublicKey(filter.Src) {
|
if !ValidatePublicKey(filter.Src) {
|
||||||
return "", errors.New("subscribe: invalid 'SignedWith' field")
|
return "", errors.New("subscribe: invalid 'SignedWith' field")
|
||||||
}
|
}
|
||||||
@ -269,9 +273,10 @@ func (api *PublicWhisperAPI) Unsubscribe(id string) {
|
|||||||
api.whisper.Unsubscribe(id)
|
api.whisper.Unsubscribe(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSubscriptionMessages retrieves all the new messages matched by a filter since the last retrieval.
|
// GetSubscriptionMessages retrieves all the new messages matched by the corresponding
|
||||||
func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*WhisperMessage {
|
// subscription filter since the last retrieval.
|
||||||
f := api.whisper.GetFilter(filterId)
|
func (api *PublicWhisperAPI) GetNewSubscriptionMessages(id string) []*WhisperMessage {
|
||||||
|
f := api.whisper.GetFilter(id)
|
||||||
if f != nil {
|
if f != nil {
|
||||||
newMail := f.Retrieve()
|
newMail := f.Retrieve()
|
||||||
return toWhisperMessages(newMail)
|
return toWhisperMessages(newMail)
|
||||||
@ -279,10 +284,10 @@ func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*Whisper
|
|||||||
return toWhisperMessages(nil)
|
return toWhisperMessages(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMessages retrieves all the floating messages that match a specific filter.
|
// GetMessages retrieves all the floating messages that match a specific subscription filter.
|
||||||
// It is likely to be called once per session, right after Subscribe call.
|
// It is likely to be called once per session, right after Subscribe call.
|
||||||
func (api *PublicWhisperAPI) GetMessages(filterId string) []*WhisperMessage {
|
func (api *PublicWhisperAPI) GetFloatingMessages(id string) []*WhisperMessage {
|
||||||
all := api.whisper.Messages(filterId)
|
all := api.whisper.Messages(id)
|
||||||
return toWhisperMessages(all)
|
return toWhisperMessages(all)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,7 +350,11 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
|
|||||||
return errors.New("post: topic is missing for symmetric encryption")
|
return errors.New("post: topic is missing for symmetric encryption")
|
||||||
}
|
}
|
||||||
} else if args.Type == "asym" {
|
} else if args.Type == "asym" {
|
||||||
params.Dst = crypto.ToECDSAPub(common.FromHex(args.Key))
|
kb := common.FromHex(args.Key)
|
||||||
|
if kb == nil {
|
||||||
|
return errors.New("post: public key for asymmetric encryption is invalid")
|
||||||
|
}
|
||||||
|
params.Dst = crypto.ToECDSAPub(kb)
|
||||||
if !ValidatePublicKey(params.Dst) {
|
if !ValidatePublicKey(params.Dst) {
|
||||||
return errors.New("post: public key for asymmetric encryption is invalid")
|
return errors.New("post: public key for asymmetric encryption is invalid")
|
||||||
}
|
}
|
||||||
@ -354,9 +363,9 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// encrypt and send
|
// encrypt and send
|
||||||
message := NewSentMessage(¶ms)
|
message, err := NewSentMessage(¶ms)
|
||||||
if message == nil {
|
if err != nil {
|
||||||
return errors.New("post: failed create new message, probably due to failed rand function (OS level)")
|
return err
|
||||||
}
|
}
|
||||||
envelope, err := message.Wrap(¶ms)
|
envelope, err := message.Wrap(¶ms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -383,7 +392,7 @@ type PostArgs struct {
|
|||||||
Type string `json:"type"` // "sym"/"asym" (symmetric or asymmetric)
|
Type string `json:"type"` // "sym"/"asym" (symmetric or asymmetric)
|
||||||
TTL uint32 `json:"ttl"` // time-to-live in seconds
|
TTL uint32 `json:"ttl"` // time-to-live in seconds
|
||||||
SignWith string `json:"signWith"` // id of the signing key
|
SignWith string `json:"signWith"` // id of the signing key
|
||||||
Key string `json:"key"` // id of encryption key
|
Key string `json:"key"` // key id (in case of sym) or public key (in case of asym)
|
||||||
Topic hexutil.Bytes `json:"topic"` // topic (4 bytes)
|
Topic hexutil.Bytes `json:"topic"` // topic (4 bytes)
|
||||||
Padding hexutil.Bytes `json:"padding"` // optional padding bytes
|
Padding hexutil.Bytes `json:"padding"` // optional padding bytes
|
||||||
Payload hexutil.Bytes `json:"payload"` // payload to be encrypted
|
Payload hexutil.Bytes `json:"payload"` // payload to be encrypted
|
||||||
@ -474,7 +483,6 @@ type WhisperMessage struct {
|
|||||||
// NewWhisperMessage converts an internal message into an API version.
|
// NewWhisperMessage converts an internal message into an API version.
|
||||||
func NewWhisperMessage(message *ReceivedMessage) *WhisperMessage {
|
func NewWhisperMessage(message *ReceivedMessage) *WhisperMessage {
|
||||||
msg := WhisperMessage{
|
msg := WhisperMessage{
|
||||||
Topic: common.ToHex(message.Topic[:]),
|
|
||||||
Payload: common.ToHex(message.Payload),
|
Payload: common.ToHex(message.Payload),
|
||||||
Padding: common.ToHex(message.Padding),
|
Padding: common.ToHex(message.Padding),
|
||||||
Timestamp: message.Sent,
|
Timestamp: message.Sent,
|
||||||
@ -483,11 +491,20 @@ func NewWhisperMessage(message *ReceivedMessage) *WhisperMessage {
|
|||||||
Hash: common.ToHex(message.EnvelopeHash.Bytes()),
|
Hash: common.ToHex(message.EnvelopeHash.Bytes()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(message.Topic) == TopicLength {
|
||||||
|
msg.Topic = common.ToHex(message.Topic[:])
|
||||||
|
}
|
||||||
if message.Dst != nil {
|
if message.Dst != nil {
|
||||||
msg.Dst = common.ToHex(crypto.FromECDSAPub(message.Dst))
|
b := crypto.FromECDSAPub(message.Dst)
|
||||||
|
if b != nil {
|
||||||
|
msg.Dst = common.ToHex(b)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if isMessageSigned(message.Raw[0]) {
|
if isMessageSigned(message.Raw[0]) {
|
||||||
msg.Src = common.ToHex(crypto.FromECDSAPub(message.SigToPubKey()))
|
b := crypto.FromECDSAPub(message.SigToPubKey())
|
||||||
|
if b != nil {
|
||||||
|
msg.Src = common.ToHex(b)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return &msg
|
return &msg
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ func TestBasic(t *testing.T) {
|
|||||||
t.Fatalf("wrong version: %d.", ver)
|
t.Fatalf("wrong version: %d.", ver)
|
||||||
}
|
}
|
||||||
|
|
||||||
mail := api.GetSubscriptionMessages("non-existent-id")
|
mail := api.GetNewSubscriptionMessages("non-existent-id")
|
||||||
if len(mail) != 0 {
|
if len(mail) != 0 {
|
||||||
t.Fatalf("failed GetFilterChanges: premature result")
|
t.Fatalf("failed GetFilterChanges: premature result")
|
||||||
}
|
}
|
||||||
@ -282,7 +282,7 @@ func waitForMessages(api *PublicWhisperAPI, id string, target int) []*WhisperMes
|
|||||||
// timeout: 2 seconds
|
// timeout: 2 seconds
|
||||||
result := make([]*WhisperMessage, 0, target)
|
result := make([]*WhisperMessage, 0, target)
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
mail := api.GetSubscriptionMessages(id)
|
mail := api.GetNewSubscriptionMessages(id)
|
||||||
if len(mail) > 0 {
|
if len(mail) > 0 {
|
||||||
for _, m := range mail {
|
for _, m := range mail {
|
||||||
result = append(result, m)
|
result = append(result, m)
|
||||||
@ -448,7 +448,7 @@ func TestIntegrationSym(t *testing.T) {
|
|||||||
f.Topics = make([][]byte, 2)
|
f.Topics = make([][]byte, 2)
|
||||||
f.Topics[0] = topics[0][:]
|
f.Topics[0] = topics[0][:]
|
||||||
f.Topics[1] = topics[1][:]
|
f.Topics[1] = topics[1][:]
|
||||||
f.MinPoW = 0.324
|
f.MinPoW = DefaultMinimumPoW / 2
|
||||||
f.SignedWith = sigPubKey.String()
|
f.SignedWith = sigPubKey.String()
|
||||||
f.AllowP2P = false
|
f.AllowP2P = false
|
||||||
|
|
||||||
@ -546,7 +546,7 @@ func TestIntegrationSymWithFilter(t *testing.T) {
|
|||||||
f.Topics = make([][]byte, 2)
|
f.Topics = make([][]byte, 2)
|
||||||
f.Topics[0] = topics[0][:]
|
f.Topics[0] = topics[0][:]
|
||||||
f.Topics[1] = topics[1][:]
|
f.Topics[1] = topics[1][:]
|
||||||
f.MinPoW = 0.324
|
f.MinPoW = DefaultMinimumPoW / 2
|
||||||
f.SignedWith = sigPubKey.String()
|
f.SignedWith = sigPubKey.String()
|
||||||
f.AllowP2P = false
|
f.AllowP2P = false
|
||||||
|
|
||||||
|
@ -28,12 +28,6 @@ func BenchmarkDeriveKeyMaterial(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkDeriveOneTimeKey(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
DeriveOneTimeKey([]byte("test value 1"), []byte("test value 2"), 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkEncryptionSym(b *testing.B) {
|
func BenchmarkEncryptionSym(b *testing.B) {
|
||||||
InitSingleTest()
|
InitSingleTest()
|
||||||
|
|
||||||
@ -43,7 +37,7 @@ func BenchmarkEncryptionSym(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
msg := NewSentMessage(params)
|
msg, _ := NewSentMessage(params)
|
||||||
_, err := msg.Wrap(params)
|
_, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Errorf("failed Wrap with seed %d: %s.", seed, err)
|
b.Errorf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -68,7 +62,7 @@ func BenchmarkEncryptionAsym(b *testing.B) {
|
|||||||
params.Dst = &key.PublicKey
|
params.Dst = &key.PublicKey
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
msg := NewSentMessage(params)
|
msg, _ := NewSentMessage(params)
|
||||||
_, err := msg.Wrap(params)
|
_, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -83,7 +77,7 @@ func BenchmarkDecryptionSymValid(b *testing.B) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
}
|
}
|
||||||
msg := NewSentMessage(params)
|
msg, _ := NewSentMessage(params)
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -105,7 +99,7 @@ func BenchmarkDecryptionSymInvalid(b *testing.B) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
}
|
}
|
||||||
msg := NewSentMessage(params)
|
msg, _ := NewSentMessage(params)
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -134,7 +128,7 @@ func BenchmarkDecryptionAsymValid(b *testing.B) {
|
|||||||
f := Filter{KeyAsym: key}
|
f := Filter{KeyAsym: key}
|
||||||
params.KeySym = nil
|
params.KeySym = nil
|
||||||
params.Dst = &key.PublicKey
|
params.Dst = &key.PublicKey
|
||||||
msg := NewSentMessage(params)
|
msg, _ := NewSentMessage(params)
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -161,7 +155,7 @@ func BenchmarkDecryptionAsymInvalid(b *testing.B) {
|
|||||||
}
|
}
|
||||||
params.KeySym = nil
|
params.KeySym = nil
|
||||||
params.Dst = &key.PublicKey
|
params.Dst = &key.PublicKey
|
||||||
msg := NewSentMessage(params)
|
msg, _ := NewSentMessage(params)
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -203,7 +197,7 @@ func BenchmarkPoW(b *testing.B) {
|
|||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
increment(params.Payload)
|
increment(params.Payload)
|
||||||
msg := NewSentMessage(params)
|
msg, _ := NewSentMessage(params)
|
||||||
_, err := msg.Wrap(params)
|
_, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
|
@ -49,18 +49,16 @@ const (
|
|||||||
paddingMask = byte(3)
|
paddingMask = byte(3)
|
||||||
signatureFlag = byte(4)
|
signatureFlag = byte(4)
|
||||||
|
|
||||||
TopicLength = 4
|
TopicLength = 4
|
||||||
signatureLength = 65
|
signatureLength = 65
|
||||||
aesKeyLength = 32
|
aesKeyLength = 32
|
||||||
saltLength = 12
|
AESNonceLength = 12
|
||||||
AESNonceMaxLength = 12
|
keyIdSize = 32
|
||||||
keyIdSize = 32
|
|
||||||
|
|
||||||
DefaultMaxMessageLength = 1024 * 1024
|
DefaultMaxMessageLength = 1024 * 1024
|
||||||
DefaultMinimumPoW = 1.0 // todo: review after testing.
|
DefaultMinimumPoW = 0.2
|
||||||
|
|
||||||
padSizeLimitLower = 128 // it can not be less - we don't want to reveal the absence of signature
|
padSizeLimit = 256 // just an arbitrary number, could be changed without breaking the protocol (must not exceed 2^24)
|
||||||
padSizeLimitUpper = 256 // just an arbitrary number, could be changed without losing compatibility
|
|
||||||
messageQueueLimit = 1024
|
messageQueueLimit = 1024
|
||||||
|
|
||||||
expirationCycle = time.Second
|
expirationCycle = time.Second
|
||||||
|
@ -40,7 +40,6 @@ type Envelope struct {
|
|||||||
Expiry uint32
|
Expiry uint32
|
||||||
TTL uint32
|
TTL uint32
|
||||||
Topic TopicType
|
Topic TopicType
|
||||||
Salt []byte
|
|
||||||
AESNonce []byte
|
AESNonce []byte
|
||||||
Data []byte
|
Data []byte
|
||||||
EnvNonce uint64
|
EnvNonce uint64
|
||||||
@ -50,15 +49,25 @@ type Envelope struct {
|
|||||||
// Don't access hash directly, use Hash() function instead.
|
// Don't access hash directly, use Hash() function instead.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// size returns the size of envelope as it is sent (i.e. public fields only)
|
||||||
|
func (e *Envelope) size() int {
|
||||||
|
return 20 + len(e.Version) + len(e.AESNonce) + len(e.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
|
||||||
|
func (e *Envelope) rlpWithoutNonce() []byte {
|
||||||
|
res, _ := rlp.EncodeToBytes([]interface{}{e.Version, e.Expiry, e.TTL, e.Topic, e.AESNonce, e.Data})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// NewEnvelope wraps a Whisper message with expiration and destination data
|
// NewEnvelope wraps a Whisper message with expiration and destination data
|
||||||
// included into an envelope for network forwarding.
|
// included into an envelope for network forwarding.
|
||||||
func NewEnvelope(ttl uint32, topic TopicType, salt []byte, aesNonce []byte, msg *SentMessage) *Envelope {
|
func NewEnvelope(ttl uint32, topic TopicType, aesNonce []byte, msg *SentMessage) *Envelope {
|
||||||
env := Envelope{
|
env := Envelope{
|
||||||
Version: make([]byte, 1),
|
Version: make([]byte, 1),
|
||||||
Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()),
|
Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()),
|
||||||
TTL: ttl,
|
TTL: ttl,
|
||||||
Topic: topic,
|
Topic: topic,
|
||||||
Salt: salt,
|
|
||||||
AESNonce: aesNonce,
|
AESNonce: aesNonce,
|
||||||
Data: msg.Raw,
|
Data: msg.Raw,
|
||||||
EnvNonce: 0,
|
EnvNonce: 0,
|
||||||
@ -126,10 +135,6 @@ func (e *Envelope) Seal(options *MessageParams) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Envelope) size() int {
|
|
||||||
return len(e.Data) + len(e.Version) + len(e.AESNonce) + len(e.Salt) + 20
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Envelope) PoW() float64 {
|
func (e *Envelope) PoW() float64 {
|
||||||
if e.pow == 0 {
|
if e.pow == 0 {
|
||||||
e.calculatePoW(0)
|
e.calculatePoW(0)
|
||||||
@ -159,12 +164,6 @@ func (e *Envelope) powToFirstBit(pow float64) int {
|
|||||||
return int(bits)
|
return int(bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
|
|
||||||
func (e *Envelope) rlpWithoutNonce() []byte {
|
|
||||||
res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Salt, e.AESNonce, e.Data})
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns the SHA3 hash of the envelope, calculating it if not yet done.
|
// Hash returns the SHA3 hash of the envelope, calculating it if not yet done.
|
||||||
func (e *Envelope) Hash() common.Hash {
|
func (e *Envelope) Hash() common.Hash {
|
||||||
if (e.hash == common.Hash{}) {
|
if (e.hash == common.Hash{}) {
|
||||||
@ -210,7 +209,7 @@ func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, erro
|
|||||||
// OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key.
|
// OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key.
|
||||||
func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) {
|
func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) {
|
||||||
msg = &ReceivedMessage{Raw: e.Data}
|
msg = &ReceivedMessage{Raw: e.Data}
|
||||||
err = msg.decryptSymmetric(key, e.Salt, e.AESNonce)
|
err = msg.decryptSymmetric(key, e.AESNonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg = nil
|
msg = nil
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func generateFilter(t *testing.T, symmetric bool) (*Filter, error) {
|
|||||||
f.Src = &key.PublicKey
|
f.Src = &key.PublicKey
|
||||||
|
|
||||||
if symmetric {
|
if symmetric {
|
||||||
f.KeySym = make([]byte, 12)
|
f.KeySym = make([]byte, aesKeyLength)
|
||||||
mrand.Read(f.KeySym)
|
mrand.Read(f.KeySym)
|
||||||
f.SymKeyHash = crypto.Keccak256Hash(f.KeySym)
|
f.SymKeyHash = crypto.Keccak256Hash(f.KeySym)
|
||||||
} else {
|
} else {
|
||||||
@ -179,7 +179,10 @@ func TestMatchEnvelope(t *testing.T) {
|
|||||||
params.Topic[0] = 0xFF // ensure mismatch
|
params.Topic[0] = 0xFF // ensure mismatch
|
||||||
|
|
||||||
// mismatch with pseudo-random data
|
// mismatch with pseudo-random data
|
||||||
msg := NewSentMessage(params)
|
msg, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -197,7 +200,10 @@ func TestMatchEnvelope(t *testing.T) {
|
|||||||
i := mrand.Int() % 4
|
i := mrand.Int() % 4
|
||||||
fsym.Topics[i] = params.Topic[:]
|
fsym.Topics[i] = params.Topic[:]
|
||||||
fasym.Topics[i] = params.Topic[:]
|
fasym.Topics[i] = params.Topic[:]
|
||||||
msg = NewSentMessage(params)
|
msg, err = NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err = msg.Wrap(params)
|
env, err = msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
|
||||||
@ -245,7 +251,10 @@ func TestMatchEnvelope(t *testing.T) {
|
|||||||
}
|
}
|
||||||
params.KeySym = nil
|
params.KeySym = nil
|
||||||
params.Dst = &key.PublicKey
|
params.Dst = &key.PublicKey
|
||||||
msg = NewSentMessage(params)
|
msg, err = NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err = msg.Wrap(params)
|
env, err = msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
|
||||||
@ -323,12 +332,14 @@ func TestMatchMessageSym(t *testing.T) {
|
|||||||
params.KeySym = f.KeySym
|
params.KeySym = f.KeySym
|
||||||
params.Topic = BytesToTopic(f.Topics[index])
|
params.Topic = BytesToTopic(f.Topics[index])
|
||||||
|
|
||||||
sentMessage := NewSentMessage(params)
|
sentMessage, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := sentMessage.Wrap(params)
|
env, err := sentMessage.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := env.Open(f)
|
msg := env.Open(f)
|
||||||
if msg == nil {
|
if msg == nil {
|
||||||
t.Fatalf("failed Open with seed %d.", seed)
|
t.Fatalf("failed Open with seed %d.", seed)
|
||||||
@ -419,12 +430,14 @@ func TestMatchMessageAsym(t *testing.T) {
|
|||||||
keySymOrig := params.KeySym
|
keySymOrig := params.KeySym
|
||||||
params.KeySym = nil
|
params.KeySym = nil
|
||||||
|
|
||||||
sentMessage := NewSentMessage(params)
|
sentMessage, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := sentMessage.Wrap(params)
|
env, err := sentMessage.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := env.Open(f)
|
msg := env.Open(f)
|
||||||
if msg == nil {
|
if msg == nil {
|
||||||
t.Fatalf("failed to open with seed %d.", seed)
|
t.Fatalf("failed to open with seed %d.", seed)
|
||||||
@ -506,7 +519,10 @@ func generateCompatibeEnvelope(t *testing.T, f *Filter) *Envelope {
|
|||||||
|
|
||||||
params.KeySym = f.KeySym
|
params.KeySym = f.KeySym
|
||||||
params.Topic = BytesToTopic(f.Topics[2])
|
params.Topic = BytesToTopic(f.Topics[2])
|
||||||
sentMessage := NewSentMessage(params)
|
sentMessage, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := sentMessage.Wrap(params)
|
env, err := sentMessage.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -678,7 +694,10 @@ func TestVariableTopics(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
}
|
}
|
||||||
msg := NewSentMessage(params)
|
msg, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
|
@ -23,14 +23,14 @@ import (
|
|||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
"crypto/sha256"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/ecies"
|
"github.com/ethereum/go-ethereum/crypto/ecies"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"golang.org/x/crypto/pbkdf2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options specifies the exact way a message should be wrapped into an Envelope.
|
// Options specifies the exact way a message should be wrapped into an Envelope.
|
||||||
@ -86,58 +86,76 @@ func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
|
|||||||
return msg.Dst != nil
|
return msg.Dst != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeriveOneTimeKey(key []byte, salt []byte, version uint64) ([]byte, error) {
|
|
||||||
if version == 0 {
|
|
||||||
derivedKey := pbkdf2.Key(key, salt, 8, aesKeyLength, sha256.New)
|
|
||||||
return derivedKey, nil
|
|
||||||
} else {
|
|
||||||
return nil, unknownVersionError(version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
|
// NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
|
||||||
func NewSentMessage(params *MessageParams) *SentMessage {
|
func NewSentMessage(params *MessageParams) (*SentMessage, error) {
|
||||||
msg := SentMessage{}
|
msg := SentMessage{}
|
||||||
msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Payload)+signatureLength+padSizeLimitUpper)
|
msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit)
|
||||||
msg.Raw[0] = 0 // set all the flags to zero
|
msg.Raw[0] = 0 // set all the flags to zero
|
||||||
err := msg.appendPadding(params)
|
err := msg.appendPadding(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to create NewSentMessage", "err", err)
|
return nil, err
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
msg.Raw = append(msg.Raw, params.Payload...)
|
msg.Raw = append(msg.Raw, params.Payload...)
|
||||||
return &msg
|
return &msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSizeOfLength returns the number of bytes necessary to encode the entire size padding (including these bytes)
|
||||||
|
func getSizeOfLength(b []byte) (sz int, err error) {
|
||||||
|
sz = intSize(len(b)) // first iteration
|
||||||
|
sz = intSize(len(b) + sz) // second iteration
|
||||||
|
if sz > 3 {
|
||||||
|
err = errors.New("oversized padding parameter")
|
||||||
|
}
|
||||||
|
return sz, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// sizeOfIntSize returns minimal number of bytes necessary to encode an integer value
|
||||||
|
func intSize(i int) (s int) {
|
||||||
|
for s = 1; i >= 256; s++ {
|
||||||
|
i /= 256
|
||||||
|
}
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// appendPadding appends the pseudorandom padding bytes and sets the padding flag.
|
// appendPadding appends the pseudorandom padding bytes and sets the padding flag.
|
||||||
// The last byte contains the size of padding (thus, its size must not exceed 256).
|
// The last byte contains the size of padding (thus, its size must not exceed 256).
|
||||||
func (msg *SentMessage) appendPadding(params *MessageParams) error {
|
func (msg *SentMessage) appendPadding(params *MessageParams) error {
|
||||||
total := len(params.Payload) + 1
|
rawSize := len(params.Payload) + 1
|
||||||
if params.Src != nil {
|
if params.Src != nil {
|
||||||
total += signatureLength
|
rawSize += signatureLength
|
||||||
}
|
}
|
||||||
padChunk := padSizeLimitUpper
|
odd := rawSize % padSizeLimit
|
||||||
if total <= padSizeLimitLower {
|
|
||||||
padChunk = padSizeLimitLower
|
if len(params.Padding) != 0 {
|
||||||
}
|
padSize := len(params.Padding)
|
||||||
odd := total % padChunk
|
padLengthSize, err := getSizeOfLength(params.Padding)
|
||||||
if odd > 0 {
|
if err != nil {
|
||||||
padSize := padChunk - odd
|
return err
|
||||||
if padSize > 255 {
|
}
|
||||||
// this algorithm is only valid if padSizeLimitUpper <= 256.
|
totalPadSize := padSize + padLengthSize
|
||||||
// if padSizeLimitUpper will ever change, please fix the algorithm
|
buf := make([]byte, 8)
|
||||||
// (for more information see ReceivedMessage.extractPadding() function).
|
binary.LittleEndian.PutUint32(buf, uint32(totalPadSize))
|
||||||
|
buf = buf[:padLengthSize]
|
||||||
|
msg.Raw = append(msg.Raw, buf...)
|
||||||
|
msg.Raw = append(msg.Raw, params.Padding...)
|
||||||
|
msg.Raw[0] |= byte(padLengthSize) // number of bytes indicating the padding size
|
||||||
|
} else if odd != 0 {
|
||||||
|
totalPadSize := padSizeLimit - odd
|
||||||
|
if totalPadSize > 255 {
|
||||||
|
// this algorithm is only valid if padSizeLimit < 256.
|
||||||
|
// if padSizeLimit will ever change, please fix the algorithm
|
||||||
|
// (please see also ReceivedMessage.extractPadding() function).
|
||||||
panic("please fix the padding algorithm before releasing new version")
|
panic("please fix the padding algorithm before releasing new version")
|
||||||
}
|
}
|
||||||
buf := make([]byte, padSize)
|
buf := make([]byte, totalPadSize)
|
||||||
_, err := crand.Read(buf[1:])
|
_, err := crand.Read(buf[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buf[0] = byte(padSize)
|
if totalPadSize > 6 && !validateSymmetricKey(buf) {
|
||||||
if params.Padding != nil {
|
return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize))
|
||||||
copy(buf[1:], params.Padding)
|
|
||||||
}
|
}
|
||||||
|
buf[0] = byte(totalPadSize)
|
||||||
msg.Raw = append(msg.Raw, buf...)
|
msg.Raw = append(msg.Raw, buf...)
|
||||||
msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size
|
msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size
|
||||||
}
|
}
|
||||||
@ -178,46 +196,31 @@ func (msg *SentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
|
|||||||
|
|
||||||
// encryptSymmetric encrypts a message with a topic key, using AES-GCM-256.
|
// encryptSymmetric encrypts a message with a topic key, using AES-GCM-256.
|
||||||
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
|
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
|
||||||
func (msg *SentMessage) encryptSymmetric(key []byte) (salt []byte, nonce []byte, err error) {
|
func (msg *SentMessage) encryptSymmetric(key []byte) (nonce []byte, err error) {
|
||||||
if !validateSymmetricKey(key) {
|
if !validateSymmetricKey(key) {
|
||||||
return nil, nil, errors.New("invalid key provided for symmetric encryption")
|
return nil, errors.New("invalid key provided for symmetric encryption")
|
||||||
}
|
}
|
||||||
|
|
||||||
salt = make([]byte, saltLength)
|
block, err := aes.NewCipher(key)
|
||||||
_, err = crand.Read(salt)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
} else if !validateSymmetricKey(salt) {
|
|
||||||
return nil, nil, errors.New("crypto/rand failed to generate salt")
|
|
||||||
}
|
|
||||||
|
|
||||||
derivedKey, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if !validateSymmetricKey(derivedKey) {
|
|
||||||
return nil, nil, errors.New("failed to derive one-time key")
|
|
||||||
}
|
|
||||||
block, err := aes.NewCipher(derivedKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
}
|
||||||
aesgcm, err := cipher.NewGCM(block)
|
aesgcm, err := cipher.NewGCM(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// never use more than 2^32 random nonces with a given key
|
// never use more than 2^32 random nonces with a given key
|
||||||
nonce = make([]byte, aesgcm.NonceSize())
|
nonce = make([]byte, aesgcm.NonceSize())
|
||||||
_, err = crand.Read(nonce)
|
_, err = crand.Read(nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
} else if !validateSymmetricKey(nonce) {
|
} else if !validateSymmetricKey(nonce) {
|
||||||
return nil, nil, errors.New("crypto/rand failed to generate nonce")
|
return nil, errors.New("crypto/rand failed to generate nonce")
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil)
|
msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil)
|
||||||
return salt, nonce, nil
|
return nonce, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap bundles the message into an Envelope to transmit over the network.
|
// Wrap bundles the message into an Envelope to transmit over the network.
|
||||||
@ -231,11 +234,11 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var salt, nonce []byte
|
var nonce []byte
|
||||||
if options.Dst != nil {
|
if options.Dst != nil {
|
||||||
err = msg.encryptAsymmetric(options.Dst)
|
err = msg.encryptAsymmetric(options.Dst)
|
||||||
} else if options.KeySym != nil {
|
} else if options.KeySym != nil {
|
||||||
salt, nonce, err = msg.encryptSymmetric(options.KeySym)
|
nonce, err = msg.encryptSymmetric(options.KeySym)
|
||||||
} else {
|
} else {
|
||||||
err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
|
err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
|
||||||
}
|
}
|
||||||
@ -244,7 +247,7 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, msg)
|
envelope = NewEnvelope(options.TTL, options.Topic, nonce, msg)
|
||||||
err = envelope.Seal(options)
|
err = envelope.Seal(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -254,13 +257,8 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
|
|||||||
|
|
||||||
// decryptSymmetric decrypts a message with a topic key, using AES-GCM-256.
|
// decryptSymmetric decrypts a message with a topic key, using AES-GCM-256.
|
||||||
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
|
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
|
||||||
func (msg *ReceivedMessage) decryptSymmetric(key []byte, salt []byte, nonce []byte) error {
|
func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error {
|
||||||
derivedKey, err := DeriveOneTimeKey(key, salt, msg.EnvelopeVersion)
|
block, err := aes.NewCipher(key)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
block, err := aes.NewCipher(derivedKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -323,7 +321,8 @@ func (msg *ReceivedMessage) Validate() bool {
|
|||||||
// can be successfully decrypted.
|
// can be successfully decrypted.
|
||||||
func (msg *ReceivedMessage) extractPadding(end int) (int, bool) {
|
func (msg *ReceivedMessage) extractPadding(end int) (int, bool) {
|
||||||
paddingSize := 0
|
paddingSize := 0
|
||||||
sz := int(msg.Raw[0] & paddingMask) // number of bytes containing the entire size of padding, could be zero
|
sz := int(msg.Raw[0] & paddingMask) // number of bytes indicating the entire size of padding (including these bytes)
|
||||||
|
// could be zero -- it means no padding
|
||||||
if sz != 0 {
|
if sz != 0 {
|
||||||
paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz]))
|
paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz]))
|
||||||
if paddingSize < sz || paddingSize+1 > end {
|
if paddingSize < sz || paddingSize+1 > end {
|
||||||
|
@ -31,9 +31,9 @@ func copyFromBuf(dst []byte, src []byte, beg int) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func generateMessageParams() (*MessageParams, error) {
|
func generateMessageParams() (*MessageParams, error) {
|
||||||
// set all the parameters except p.Dst
|
// set all the parameters except p.Dst and p.Padding
|
||||||
|
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 4)
|
||||||
mrand.Read(buf)
|
mrand.Read(buf)
|
||||||
sz := mrand.Intn(400)
|
sz := mrand.Intn(400)
|
||||||
|
|
||||||
@ -42,14 +42,10 @@ func generateMessageParams() (*MessageParams, error) {
|
|||||||
p.WorkTime = 1
|
p.WorkTime = 1
|
||||||
p.TTL = uint32(mrand.Intn(1024))
|
p.TTL = uint32(mrand.Intn(1024))
|
||||||
p.Payload = make([]byte, sz)
|
p.Payload = make([]byte, sz)
|
||||||
p.Padding = make([]byte, padSizeLimitUpper)
|
|
||||||
p.KeySym = make([]byte, aesKeyLength)
|
p.KeySym = make([]byte, aesKeyLength)
|
||||||
|
mrand.Read(p.Payload)
|
||||||
var b int
|
mrand.Read(p.KeySym)
|
||||||
b = copyFromBuf(p.Payload, buf, b)
|
p.Topic = BytesToTopic(buf)
|
||||||
b = copyFromBuf(p.Padding, buf, b)
|
|
||||||
b = copyFromBuf(p.KeySym, buf, b)
|
|
||||||
p.Topic = BytesToTopic(buf[b:])
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
p.Src, err = crypto.GenerateKey()
|
p.Src, err = crypto.GenerateKey()
|
||||||
@ -77,11 +73,12 @@ func singleMessageTest(t *testing.T, symmetric bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
text := make([]byte, 0, 512)
|
text := make([]byte, 0, 512)
|
||||||
steg := make([]byte, 0, 512)
|
|
||||||
text = append(text, params.Payload...)
|
text = append(text, params.Payload...)
|
||||||
steg = append(steg, params.Padding...)
|
|
||||||
|
|
||||||
msg := NewSentMessage(params)
|
msg, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -102,10 +99,6 @@ func singleMessageTest(t *testing.T, symmetric bool) {
|
|||||||
t.Fatalf("failed to validate with seed %d.", seed)
|
t.Fatalf("failed to validate with seed %d.", seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
padsz := len(decrypted.Padding)
|
|
||||||
if !bytes.Equal(steg[:padsz], decrypted.Padding) {
|
|
||||||
t.Fatalf("failed with seed %d: compare padding.", seed)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(text, decrypted.Payload) {
|
if !bytes.Equal(text, decrypted.Payload) {
|
||||||
t.Fatalf("failed with seed %d: compare payload.", seed)
|
t.Fatalf("failed with seed %d: compare payload.", seed)
|
||||||
}
|
}
|
||||||
@ -140,7 +133,10 @@ func TestMessageWrap(t *testing.T) {
|
|||||||
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := NewSentMessage(params)
|
msg, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
params.TTL = 1
|
params.TTL = 1
|
||||||
params.WorkTime = 12
|
params.WorkTime = 12
|
||||||
params.PoW = target
|
params.PoW = target
|
||||||
@ -155,7 +151,10 @@ func TestMessageWrap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set PoW target too high, expect error
|
// set PoW target too high, expect error
|
||||||
msg2 := NewSentMessage(params)
|
msg2, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
params.TTL = 1000000
|
params.TTL = 1000000
|
||||||
params.WorkTime = 1
|
params.WorkTime = 1
|
||||||
params.PoW = 10000000.0
|
params.PoW = 10000000.0
|
||||||
@ -175,14 +174,15 @@ func TestMessageSeal(t *testing.T) {
|
|||||||
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := NewSentMessage(params)
|
msg, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
params.TTL = 1
|
params.TTL = 1
|
||||||
aesnonce := make([]byte, 12)
|
aesnonce := make([]byte, 12)
|
||||||
salt := make([]byte, 12)
|
|
||||||
mrand.Read(aesnonce)
|
mrand.Read(aesnonce)
|
||||||
mrand.Read(salt)
|
|
||||||
|
|
||||||
env := NewEnvelope(params.TTL, params.Topic, salt, aesnonce, msg)
|
env := NewEnvelope(params.TTL, params.Topic, aesnonce, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
}
|
}
|
||||||
@ -236,11 +236,12 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
text := make([]byte, 0, 512)
|
text := make([]byte, 0, 512)
|
||||||
steg := make([]byte, 0, 512)
|
|
||||||
text = append(text, params.Payload...)
|
text = append(text, params.Payload...)
|
||||||
steg = append(steg, params.Padding...)
|
|
||||||
|
|
||||||
msg := NewSentMessage(params)
|
msg, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -252,10 +253,6 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) {
|
|||||||
t.Fatalf("failed to open with seed %d.", seed)
|
t.Fatalf("failed to open with seed %d.", seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
padsz := len(decrypted.Padding)
|
|
||||||
if !bytes.Equal(steg[:padsz], decrypted.Padding) {
|
|
||||||
t.Fatalf("failed with seed %d: compare padding.", seed)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(text, decrypted.Payload) {
|
if !bytes.Equal(text, decrypted.Payload) {
|
||||||
t.Fatalf("failed with seed %d: compare payload.", seed)
|
t.Fatalf("failed with seed %d: compare payload.", seed)
|
||||||
}
|
}
|
||||||
@ -291,21 +288,38 @@ func TestEncryptWithZeroKey(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
}
|
}
|
||||||
|
msg, err := NewSentMessage(params)
|
||||||
msg := NewSentMessage(params)
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
params.KeySym = make([]byte, aesKeyLength)
|
params.KeySym = make([]byte, aesKeyLength)
|
||||||
_, err = msg.Wrap(params)
|
_, err = msg.Wrap(params)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("wrapped with zero key, seed: %d.", seed)
|
t.Fatalf("wrapped with zero key, seed: %d.", seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
params, err = generateMessageParams()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
|
msg, err = NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
params.KeySym = make([]byte, 0)
|
params.KeySym = make([]byte, 0)
|
||||||
_, err = msg.Wrap(params)
|
_, err = msg.Wrap(params)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("wrapped with empty key, seed: %d.", seed)
|
t.Fatalf("wrapped with empty key, seed: %d.", seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
params, err = generateMessageParams()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
|
msg, err = NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
params.KeySym = nil
|
params.KeySym = nil
|
||||||
_, err = msg.Wrap(params)
|
_, err = msg.Wrap(params)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -320,7 +334,10 @@ func TestRlpEncode(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
}
|
}
|
||||||
msg := NewSentMessage(params)
|
msg, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("wrapped with zero key, seed: %d.", seed)
|
t.Fatalf("wrapped with zero key, seed: %d.", seed)
|
||||||
@ -344,3 +361,60 @@ func TestRlpEncode(t *testing.T) {
|
|||||||
t.Fatalf("Hashes are not equal: %x vs. %x", he, hd)
|
t.Fatalf("Hashes are not equal: %x vs. %x", he, hd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func singlePaddingTest(t *testing.T, padSize int) {
|
||||||
|
params, err := generateMessageParams()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed generateMessageParams with seed %d and sz=%d: %s.", seed, padSize, err)
|
||||||
|
}
|
||||||
|
params.Padding = make([]byte, padSize)
|
||||||
|
params.PoW = 0.0000000001
|
||||||
|
pad := make([]byte, padSize)
|
||||||
|
_, err = mrand.Read(pad)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("padding is not generated (seed %d): %s", seed, err)
|
||||||
|
}
|
||||||
|
n := copy(params.Padding, pad)
|
||||||
|
if n != padSize {
|
||||||
|
t.Fatalf("padding is not copied (seed %d): %s", seed, err)
|
||||||
|
}
|
||||||
|
msg, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
|
env, err := msg.Wrap(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to wrap, seed: %d and sz=%d.", seed, padSize)
|
||||||
|
}
|
||||||
|
f := Filter{KeySym: params.KeySym}
|
||||||
|
decrypted := env.Open(&f)
|
||||||
|
if decrypted == nil {
|
||||||
|
t.Fatalf("failed to open, seed and sz=%d: %d.", seed, padSize)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(pad, decrypted.Padding) {
|
||||||
|
t.Fatalf("padding is not retireved as expected with seed %d and sz=%d:\n[%x]\n[%x].", seed, padSize, pad, decrypted.Padding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPadding(t *testing.T) {
|
||||||
|
InitSingleTest()
|
||||||
|
|
||||||
|
for i := 1; i < 260; i++ {
|
||||||
|
singlePaddingTest(t, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
lim := 256 * 256
|
||||||
|
for i := lim - 5; i < lim+2; i++ {
|
||||||
|
singlePaddingTest(t, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
n := mrand.Intn(256*254) + 256
|
||||||
|
singlePaddingTest(t, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
n := mrand.Intn(256*1024) + 256*256
|
||||||
|
singlePaddingTest(t, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -149,23 +149,22 @@ func (peer *Peer) expire() {
|
|||||||
// broadcast iterates over the collection of envelopes and transmits yet unknown
|
// broadcast iterates over the collection of envelopes and transmits yet unknown
|
||||||
// ones over the network.
|
// ones over the network.
|
||||||
func (p *Peer) broadcast() error {
|
func (p *Peer) broadcast() error {
|
||||||
// Fetch the envelopes and collect the unknown ones
|
var cnt int
|
||||||
envelopes := p.host.Envelopes()
|
envelopes := p.host.Envelopes()
|
||||||
transmit := make([]*Envelope, 0, len(envelopes))
|
|
||||||
for _, envelope := range envelopes {
|
for _, envelope := range envelopes {
|
||||||
if !p.marked(envelope) {
|
if !p.marked(envelope) {
|
||||||
transmit = append(transmit, envelope)
|
err := p2p.Send(p.ws, messagesCode, envelope)
|
||||||
p.mark(envelope)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
p.mark(envelope)
|
||||||
|
cnt++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(transmit) == 0 {
|
if cnt > 0 {
|
||||||
return nil
|
log.Trace("broadcast", "num. messages", cnt)
|
||||||
}
|
}
|
||||||
// Transmit the unknown batch (potentially empty)
|
|
||||||
if err := p2p.Send(p.ws, messagesCode, transmit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Trace("broadcast", "num. messages", len(transmit))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +265,10 @@ func sendMsg(t *testing.T, expected bool, id int) {
|
|||||||
opt.Payload = opt.Payload[1:]
|
opt.Payload = opt.Payload[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := NewSentMessage(&opt)
|
msg, err := NewSentMessage(&opt)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
envelope, err := msg.Wrap(&opt)
|
envelope, err := msg.Wrap(&opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to seal message: %s", err)
|
t.Fatalf("failed to seal message: %s", err)
|
||||||
@ -286,7 +289,10 @@ func TestPeerBasic(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
params.PoW = 0.001
|
params.PoW = 0.001
|
||||||
msg := NewSentMessage(params)
|
msg, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d.", seed)
|
t.Fatalf("failed Wrap with seed %d.", seed)
|
||||||
|
@ -262,24 +262,14 @@ func (w *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
|
|||||||
// GenerateSymKey generates a random symmetric key and stores it under id,
|
// 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.
|
// which is then returned. Will be used in the future for session key exchange.
|
||||||
func (w *Whisper) GenerateSymKey() (string, error) {
|
func (w *Whisper) GenerateSymKey() (string, error) {
|
||||||
const size = aesKeyLength * 2
|
key := make([]byte, aesKeyLength)
|
||||||
buf := make([]byte, size)
|
_, err := crand.Read(key)
|
||||||
_, err := crand.Read(buf)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
} else if !validateSymmetricKey(buf) {
|
} else if !validateSymmetricKey(key) {
|
||||||
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
|
|
||||||
} else if !validateSymmetricKey(derived) {
|
|
||||||
return "", fmt.Errorf("failed to derive valid key")
|
|
||||||
}
|
|
||||||
|
|
||||||
id, err := GenerateRandomID()
|
id, err := GenerateRandomID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to generate ID: %s", err)
|
return "", fmt.Errorf("failed to generate ID: %s", err)
|
||||||
@ -291,7 +281,7 @@ func (w *Whisper) GenerateSymKey() (string, error) {
|
|||||||
if w.symKeys[id] != nil {
|
if w.symKeys[id] != nil {
|
||||||
return "", fmt.Errorf("failed to generate unique ID")
|
return "", fmt.Errorf("failed to generate unique ID")
|
||||||
}
|
}
|
||||||
w.symKeys[id] = derived
|
w.symKeys[id] = key
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,6 +385,9 @@ func (w *Whisper) Unsubscribe(id string) error {
|
|||||||
// network in the coming cycles.
|
// network in the coming cycles.
|
||||||
func (w *Whisper) Send(envelope *Envelope) error {
|
func (w *Whisper) Send(envelope *Envelope) error {
|
||||||
ok, err := w.add(envelope)
|
ok, err := w.add(envelope)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("failed to add envelope")
|
return fmt.Errorf("failed to add envelope")
|
||||||
}
|
}
|
||||||
@ -469,21 +462,18 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
|||||||
log.Warn("unxepected status message received", "peer", p.peer.ID())
|
log.Warn("unxepected status message received", "peer", p.peer.ID())
|
||||||
case messagesCode:
|
case messagesCode:
|
||||||
// decode the contained envelopes
|
// decode the contained envelopes
|
||||||
var envelopes []*Envelope
|
var envelope Envelope
|
||||||
if err := packet.Decode(&envelopes); err != nil {
|
if err := packet.Decode(&envelope); err != nil {
|
||||||
log.Warn("failed to decode envelope, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
log.Warn("failed to decode envelope, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
||||||
return errors.New("invalid envelope")
|
return errors.New("invalid envelope")
|
||||||
}
|
}
|
||||||
// inject all envelopes into the internal pool
|
cached, err := wh.add(&envelope)
|
||||||
for _, envelope := range envelopes {
|
if err != nil {
|
||||||
cached, err := wh.add(envelope)
|
log.Warn("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
||||||
if err != nil {
|
return errors.New("invalid envelope")
|
||||||
log.Warn("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
}
|
||||||
return errors.New("invalid envelope")
|
if cached {
|
||||||
}
|
p.mark(&envelope)
|
||||||
if cached {
|
|
||||||
p.mark(envelope)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case p2pCode:
|
case p2pCode:
|
||||||
// peer-to-peer message, sent directly to peer bypassing PoW checks, etc.
|
// peer-to-peer message, sent directly to peer bypassing PoW checks, etc.
|
||||||
@ -550,14 +540,11 @@ func (wh *Whisper) add(envelope *Envelope) (bool, error) {
|
|||||||
return false, fmt.Errorf("oversized version [%x]", envelope.Hash())
|
return false, fmt.Errorf("oversized version [%x]", envelope.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(envelope.AESNonce) > AESNonceMaxLength {
|
aesNonceSize := len(envelope.AESNonce)
|
||||||
// the standard AES GSM nonce size is 12,
|
if aesNonceSize != 0 && aesNonceSize != AESNonceLength {
|
||||||
// but const gcmStandardNonceSize cannot be accessed directly
|
// the standard AES GCM nonce size is 12 bytes,
|
||||||
return false, fmt.Errorf("oversized AESNonce [%x]", envelope.Hash())
|
// but constant gcmStandardNonceSize cannot be accessed (not exported)
|
||||||
}
|
return false, fmt.Errorf("wrong size of AESNonce: %d bytes [env: %x]", aesNonceSize, envelope.Hash())
|
||||||
|
|
||||||
if len(envelope.Salt) > saltLength {
|
|
||||||
return false, fmt.Errorf("oversized salt [%x]", envelope.Hash())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if envelope.PoW() < wh.minPoW {
|
if envelope.PoW() < wh.minPoW {
|
||||||
|
@ -455,7 +455,10 @@ func TestExpiry(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
params.TTL = 1
|
params.TTL = 1
|
||||||
msg := NewSentMessage(params)
|
msg, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -515,7 +518,10 @@ func TestCustomization(t *testing.T) {
|
|||||||
params.Topic = BytesToTopic(f.Topics[2])
|
params.Topic = BytesToTopic(f.Topics[2])
|
||||||
params.PoW = smallPoW
|
params.PoW = smallPoW
|
||||||
params.TTL = 3600 * 24 // one day
|
params.TTL = 3600 * 24 // one day
|
||||||
msg := NewSentMessage(params)
|
msg, err := NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err := msg.Wrap(params)
|
env, err := msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
@ -533,7 +539,10 @@ func TestCustomization(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
params.TTL++
|
params.TTL++
|
||||||
msg = NewSentMessage(params)
|
msg, err = NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
env, err = msg.Wrap(params)
|
env, err = msg.Wrap(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||||
|
Loading…
Reference in New Issue
Block a user