Sending an encrypted message
Send an encrypted message that only can be read by the recipient account.
Prerequisites
- Finish the getting started section.
- Finish the sending a transfer transaction guide.
- XPX-Chain-SDK or XPX-Chain-CLI.
- A text editor or IDE.
- An account with
XPX
.
Background
Imagine that Alice wants to timestamp a sensitive message to send to an account representing her academic certificate.
Alice knows that sending a transfer transaction with a plain message through the public network will make the content of the message publicly available.
Thus, Alice sends an encrypted message that is only readable by herself and those with access to the academic certificate.
Getting into some code
- Create an account for Alice, and another for the certificate using
xpx2-cli
.
xpx2-cli account generate --save
Introduce network type (MIJIN_TEST, MIJIN, MAIN_NET, TEST_NET): TEST_NET
Do you want to save it? [y/n]: y
Introduce Sirius Chain Node URL. (Example: http://bctestnet1.brimstone.xpxsirius.io:3000): http://bctestnet1.brimstone.xpxsirius.io:3000
Insert profile name (blank means default and it could overwrite the previous profile): alice
xpx2-cli account generate --save
Introduce network type (MIJIN_TEST, MIJIN, MAIN_NET, TEST_NET): TEST_NET
Do you want to save it? [y/n]: y
Introduce Sirius Chain Node URL. (Example: http://bctestnet1.brimstone.xpxsirius.io:3000): http://bctestnet1.brimstone.xpxsirius.io:3000
Insert profile name (blank means default and it could overwrite the previous profile): certificate
- Create an encrypted message for the certificate, signing it with Alice’s account.
conf, err := sdk.NewConfig(context.Background(), []string{"http://bctestnet1.brimstone.xpxsirius.io:3000"})
if err != nil {
panic(err)
}
// Use the default http client
client := sdk.NewClient(nil, conf)
aliceAccount, err := client.NewAccountFromPrivateKey(os.Getenv("ALICE_PRIVATE_KEY"))
if err != nil {
panic(err)
}
certificateAccount, err := client.NewAccountFromPublicKey(os.Getenv("CERTIFICATE_PUBLIC_KEY"))
if err != nil {
panic(err)
}
encryptedMessage, err := aliceAccount.EncryptMessage("This message is secret", certificateAccount)
if err != nil {
panic(err)
}
const privateKey = '<privateKey>';
const aliceAccount = Account.createFromPrivateKey(privateKey, NetworkType.TEST_NET);
const certificateAccountPublicKey = '<publicKey>';
const certificatePublicAccount = PublicAccount.createFromPublicKey(certificateAccountPublicKey, NetworkType.TEST_NET);
const networkGenerationHash = process.env.NETWORK_GENERATION_HASH as string;
- Attach the encrypted message to a transfer transaction, setting the certificate address as the recipient.
transferTransaction, err := client.NewTransferTransaction(
sdk.NewDeadline(time.Hour),
certificateAccount.Address,
[]*sdk.Mosaic{sdk.XpxRelative(10)},
encryptedMessage,
)
if err != nil {
panic(err)
}
const transferTransaction = TransferTransaction.create(
Deadline.create(),
certificatePublicAccount.address,
[],
aliceAccount.encryptMessage('This message is secret', certificatePublicAccount),
NetworkType.TEST_NET);
- Sign the transaction with Alice’s account.
signedTransaction, err := aliceAccount.Sign(transferTransaction)
if err != nil {
panic(err)
}
const signedTransaction = aliceAccount.sign(transferTransaction, networkGenerationHash);
- Once signed, announce the transaction to the network.
transactionHash, err := client.Transaction.Announce(context.Background(), signedTransaction)
if err != nil {
panic(err)
}
const transactionHttp = new TransactionHttp('http://bctestnet1.brimstone.xpxsirius.io:3000');
var transactionHash = signedTransaction.hash;
transactionHttp
.announce(signedTransaction)
.subscribe(x => console.log(x), err => console.error(err));
- After the transaction gets confirmed, fetch it using the transaction hash output from (5). You can now decrypt the message using either the certificate account or address account.
transactionInfo, err := client.Transaction.GetTransaction(context.Background(), transactionHash)
if err != nil {
panic(err)
}
const certificatePrivateKey = '<privateKey>';
const certificateAccount = Account.createFromPrivateKey(certificatePrivateKey, NetworkType.TEST_NET);
const alicePublicKey = '<publicKey>';
const alicePublicAccount = PublicAccount.createFromPublicKey(alicePublicKey, NetworkType.TEST_NET);
transactionHttp.getTransaction(transactionHash)
.subscribe((transaction) => {
var plainMessage = certificateAccount.decryptMessage(new EncryptedMessage(transaction.message), alicePublicAccount);
});
If you managed to read the message, try to decrypt it using another unrelated account to ensure that only the defined participants can read the encrypted content.