package api
import (
"github.com/keys-pub/keys"
"github.com/keys-pub/keys/api"
"github.com/keys-pub/keys/dstore/events"
"github.com/pkg/errors"
"github.com/vmihailenco/msgpack/v4"
)
func Encrypt(i interface{}, sender *keys.EdX25519Key, recipient keys.ID) ([]byte, error) {
pk := api.NewKey(recipient).AsX25519Public()
if pk == nil {
return nil, errors.Errorf("invalid message recipient")
}
b, err := msgpack.Marshal(i)
if err != nil {
return nil, err
}
sk := sender.X25519Key()
encrypted := keys.BoxSeal(b, pk, sk)
box := append(sk.Public(), encrypted...)
anonymized := keys.CryptoBoxSeal(box, pk)
return anonymized, nil
}
func DecryptMessage(b []byte, key *keys.EdX25519Key) (*Message, error) {
var message Message
pk, err := Decrypt(b, &message, key)
if err != nil {
return nil, err
}
expected := api.NewKey(message.Sender).AsX25519Public()
if pk.ID() != expected.ID() {
return nil, errors.Errorf("message sender mismatch")
}
return &message, nil
}
func Decrypt(b []byte, v interface{}, key *keys.EdX25519Key) (*keys.X25519PublicKey, error) {
box, err := keys.CryptoBoxSealOpen(b, key.X25519Key())
if err != nil {
return nil, errors.Wrapf(err, "failed to decrypt message")
}
if len(box) < 32 {
return nil, errors.Wrapf(errors.Errorf("not enough bytes"), "failed to decrypt message")
}
pk := keys.NewX25519PublicKey(keys.Bytes32(box[:32]))
encrypted := box[32:]
decrypted, err := keys.BoxOpen(encrypted, pk, key.X25519Key())
if err != nil {
return nil, errors.Wrapf(err, "failed to decrypt message")
}
if err := msgpack.Unmarshal(decrypted, v); err != nil {
return nil, errors.Wrapf(err, "failed to unmarshal message")
}
return pk, nil
}
func DecryptMessageFromEvent(event *events.Event, key *keys.EdX25519Key) (*Message, error) {
message, err := DecryptMessage(event.Data, key)
if err != nil {
return nil, err
}
message.RemoteIndex = event.Index
message.RemoteTimestamp = event.Timestamp
return message, nil
}