はじめに
以前、symbol-sdkのv3.0.7で、転送トランザクションを作成した際、暗号化メッセージがウォレットで復号できないことがありました。
その記事のコメント欄に、 @Toshi_ma さんからこんなコメントを頂いておりました。
sdk v2ではRawMessageやEncryptoMessageをなぜか二重に16進数にしていました
そのため、メッセージ周りについては諦めていたのですが、このたび、symbol-sdkのアップデートでそのあたりができるようになったみたいです。
symbol-sdkのv3.0.11のリリースノートを見てみます。
(Symbol-only) special handling for encrypted messages created by Symbol wallets
special handlingとは何なのかについて、コミットを追ってみてみます。
おそらくはこのコミットなのですが、tryDecodeDeprecated
と encodeDeprecated
が追加されているようです。
なので、この処理を使うことでウォレットでメッセージを読んだり、ウォレットで送ったメッセージが読めるようになったりするのではないかと思いました。
それでは試してみましょう。
ウォレットでメッセージを読む
symbol-sdkで暗号化メッセージを作成し、トランザクションを送信します。そのトランザクションをウォレットで開いてみます。
TypeScriptのコードを示します。symbol-sdkはv3.1.0を使用しています。
import symbolSdk from 'symbol-sdk'
import axios from 'axios'
import { TextEncoder } from 'util';
const NODE_URL = process.env.NODE_URL
const PRIVATE_KEY = process.env.PRIVATE_KEY
const PUBLIC_KEY_RECEIVER = process.env.PUBLIC_KEY_RECEIVER
const network = symbolSdk.symbol.Network.TESTNET
const deadline = network.fromDatetime(new Date(Date.now() + 60000)).timestamp
const facade = new symbolSdk.facade.SymbolFacade(network.name)
const privateKey = new symbolSdk.PrivateKey(PRIVATE_KEY)
const keyPair = new symbolSdk.symbol.KeyPair(privateKey)
const currencyMosaicId = 0x72C0212E67A08BCEn
ここから暗号化メッセージの作成に入ります。encodeDeprecated
を使用します。
const textEncoder = new TextEncoder();
const messageEncoder = new symbolSdk.symbol.MessageEncoder(keyPair);
const message = messageEncoder.encodeDeprecated(
new symbolSdk.PublicKey(PUBLIC_KEY_RECEIVER),
textEncoder.encode('sample message')
)
JSDocに@deprecated
がついているためでしょうか、エディター上では取り消し線がつきました。
あとはトランザクションを作って送信します。
const transaction = facade.transactionFactory.create({
type: 'transfer_transaction_v1',
signerPublicKey: keyPair.publicKey.toString(),
fee: 1000000n,
deadline,
recipientAddress: 'TARDV42KTAIZEF64EQT4NXT7K55DHWBEFIXVJQY',
mosaics: [{ mosaicId: currencyMosaicId, amount: 1000000n }],
message
})
const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = symbolSdk.symbol.SymbolTransactionFactory.attachSignature(transaction, signature)
const hash = facade.hashTransaction(transaction).toString();
await axios.put(`${NODE_URL}/transactions`, JSON.parse(jsonPayload));
さて、このトランザクションをウォレットで開いてみます。上記のコードで使用したアカウントをウォレットにもインポートしておきます。
メッセージ欄は、暗号化メッセージを示す******
になっています。
Decryptボタンを押して復号してみます。
無事復号することができました。
ウォレットから送信したメッセージを読む
次は、ウォレットで暗号化メッセージを含んだ転送トランザクションを作成し、そのメッセージをsymbol-sdkで復号してみます。
まずはウォレットで暗号化メッセージを含んだトランザクションを作成し送信します。
次にTypeScriptのコードを示します。symbol-sdkはv3.1.0を使用しています。
import symbolSdk from 'symbol-sdk'
import axios from 'axios'
const NODE_URL = process.env.NODE_URL
const PRIVATE_KEY = process.env.PRIVATE_KEY
const PUBLIC_KEY_RECEIVER = process.env.PUBLIC_KEY_RECEIVER
const hash = 'D642F3D6394850362EC0F9C4B31F2C3F37391864C9EFC19AC987CBC405E560A5'
const transactionResponse = await axios.get(`${NODE_URL}/transactions/confirmed/${hash}`)
const encryptedMessage = transactionResponse.data.transaction.message
const privateKey = new symbolSdk.PrivateKey(PRIVATE_KEY)
const keyPair = new symbolSdk.symbol.KeyPair(privateKey)
const messageEncoder = new symbolSdk.symbol.MessageEncoder(keyPair);
const messageDecoded = messageEncoder.tryDecodeDeprecated(
new symbolSdk.PublicKey(PUBLIC_KEY_RECEIVER),
symbolSdk.utils.hexToUint8(encryptedMessage)
)
const textDecoder = new TextDecoder();
console.log(textDecoder.decode(messageDecoded.message));
tryDecodeDeprecated
を使用しています。こちらも取り消し線が付きました。
これを実行します。
ちゃんと復号できました。
平文メッセージは問題なし
おまけ。平文のメッセージのほうも見ていきましょう。
結論から言うと、symbol-sdkで送った平文メッセージは、special handling
をすることなくウォレットで開くことができました。
以下のように、先頭に0x00
を付けることが必要です。
const textEncoder = new TextEncoder();
const message = new Uint8Array([0x00, ...textEncoder.encode('あいうえお')]);
ウォレットで開くことができます。
次に、ウォレットで送ったメッセージをsymbol-sdkで開いてみます。
ウォレットでは、このように送りました。
さて、まずは
const hash = "<your_transaction_hash>"
const transactionResponse = await axios.get(`${NODE_URL}/transactions/confirmed/${hash}`)
const plainMessageHex = transactionResponse.data.transaction.message
console.log(plainMessageHex)
このコードを実行すると、以下のようにでてきます。
00E3818BE3818DE3818FE38191E38193
先頭の1バイトの0x00
は、平文メッセージを意味するヘッダーになります。「か」はUTF-8ではE3818B
であることからもわかります。
ですので、以下のように先頭バイトを取り除く必要があります。
const plainMessageUint8 = symbolSdk.utils.hexToUint8(plainMessageHex)
console.log(textDecoder.decode(plainMessageUint8.slice(1)))
これらを実行すると、
かきくけこ
と出力されました。
おわりに
以前できなかったウォレットにおける暗号化メッセージのやりとりができるようになりました。
非推奨のマークが付けられていますが、それ専用のメソッドを使うことで実現していることがわかりました。
これで新しいsymbol-sdkでも、過去のメッセージを読むことができるようになりました。