public const int MAX_MESSAGELENGTH_RELAY = 3 + 2 + 16 * 1024; //! bytes (+3 for OP_NOP OP_NOP OP_RETURN, +2 for the pushdata opcodes) public Script GenerateScriptPubKey(string message, string messageRecipient, string replyToAddress, string rewardAddress, bool encryptMessage, RsaPublicKey publicKey, RsaPrivateKey privateKey) { byte[] pushData = null; var wsm = new WantedSystemMessage() { Encryption = (encryptMessage ? MessageEncryption.RSA4096AES256 : MessageEncryption.None), Text = message, Metadata = new WantedSystemMessageMetadata() { CreationTimeUtc = DateTime.UtcNow.ToString(), RecipientAddress = messageRecipient, ReplyToAddress = replyToAddress, RewardAddress = rewardAddress } }; if (encryptMessage) { pushData = GenerateWantedSystemMessagePushData(wsm, publicKey); } else { pushData = GenerateWantedSystemMessagePushData(wsm); } return(GenerateScriptPubKey(pushData)); }
private byte[] GenerateWantedSystemMessagePushData(WantedSystemMessage message, RsaPublicKey publicKey = null) { byte[] encryptionKey = new byte[0]; string metadata = JsonConvert.SerializeObject(message.Metadata); byte[] uncompressedMetadata = System.Text.Encoding.UTF8.GetBytes(metadata); byte[] compressedMetadata = GZIPCompressByteArray(uncompressedMetadata); byte[] uncompressedMessage = System.Text.Encoding.UTF8.GetBytes(message.Text); if (message.Encryption == MessageEncryption.RSA4096AES256) { byte[] aesKey = GetRandomData(256); encryptionKey = RSAEncryptByteArray(aesKey, publicKey); byte[] encryptedMessage = AESEncryptByteArray(uncompressedMessage, aesKey); uncompressedMessage = encryptedMessage; } byte[] compressedMessage = GZIPCompressByteArray(uncompressedMessage); byte[] header = System.Text.Encoding.UTF8.GetBytes("TWS"); byte version = (byte)message.Version; byte compression = (byte)message.Compression; byte checksumType = (byte)message.ChecksumType; byte encryptionType = (byte)message.Encryption; ushort encryptionKeyLength = (ushort)encryptionKey.Length; ushort metadataLength = (ushort)compressedMetadata.Length; ushort messageLength = (ushort)compressedMessage.Length; List <byte> pushDataList = new List <byte>(); pushDataList.AddRange(header); pushDataList.Add(version); pushDataList.Add(compression); pushDataList.Add(checksumType); pushDataList.Add(encryptionType); pushDataList.AddRange(BitConverter.GetBytes(encryptionKeyLength)); pushDataList.AddRange(BitConverter.GetBytes(metadataLength)); pushDataList.AddRange(BitConverter.GetBytes(messageLength)); pushDataList.AddRange(encryptionKey); pushDataList.AddRange(compressedMetadata); pushDataList.AddRange(compressedMessage); if (pushDataList.Count > 16 * 1024) { throw new Exception("Push data can't be bigger than 16 kbytes."); } return(pushDataList.ToArray()); }
public WantedSystemMessage GetWantedSystemMessage(Script scriptPubKey, RsaPrivateKey privateKey = null) { var msg = new WantedSystemMessage(); if (scriptPubKey.Length < 13) { throw new Exception("This ScriptPubKey is not a valid Wanted System message."); } Op[] scriptPubKeyOps = scriptPubKey.ToOps().ToArray(); if ((scriptPubKeyOps[0].Code != OpcodeType.OP_NOP) || (scriptPubKeyOps[1].Code != OpcodeType.OP_NOP) || (scriptPubKeyOps[2].Code != OpcodeType.OP_RETURN)) { throw new Exception("This ScriptPubKey is not a valid Wanted System message."); } byte[] pd = scriptPubKeyOps[3].PushData; byte[] header = pd.Take <byte>(3).ToArray(); msg.Version = pd[3]; if (msg.Version != 1) { throw new Exception($"Wanted System message vesion {msg.Version} is not supported."); } msg.Compression = (MessageCompression)pd[4]; if (msg.Compression != MessageCompression.GZip) { throw new Exception($"Wanted System message compression {msg.Compression} is not supported."); } msg.ChecksumType = (MessageChecksum)pd[5]; if (msg.ChecksumType != MessageChecksum.None) { throw new Exception($"Wanted System message checksum {msg.ChecksumType} is not supported."); } msg.Encryption = (MessageEncryption)pd[6]; if (msg.Encryption != MessageEncryption.RSA4096AES256) { throw new Exception($"Wanted System message encryption {msg.Encryption} is not supported."); } ushort encryptionKeyLength = BitConverter.ToUInt16(pd, 7); ushort metadataLength = BitConverter.ToUInt16(pd, 9); ushort messageLength = BitConverter.ToUInt16(pd, 11); byte[] encryptionKey = new byte[encryptionKeyLength]; byte[] compressedMetadata = new byte[metadataLength]; byte[] compressedMessage = new byte[messageLength]; Array.Copy(pd, 13, encryptionKey, 0, encryptionKeyLength); Array.Copy(pd, 13 + encryptionKeyLength, compressedMetadata, 0, metadataLength); Array.Copy(pd, 13 + encryptionKeyLength + metadataLength, compressedMessage, 0, messageLength); byte[] uncompressedMetadata = GZIPDecompressByteArray(compressedMetadata); byte[] uncompressedMessage = GZIPDecompressByteArray(compressedMessage); // process metadata using json serializer string metadata = System.Text.Encoding.UTF8.GetString(uncompressedMetadata); msg.Metadata = JsonConvert.DeserializeObject <WantedSystemMessageMetadata>(metadata); // Decrypt the message if needed if (msg.Encryption == MessageEncryption.RSA4096AES256) { if (privateKey == null) { throw new Exception("The message is encrypted but the decryption key was not provided."); } byte[] aesKey = null; try { aesKey = RSADecryptByteArray(encryptionKey, privateKey); } catch { throw new Exception("The private key you provided isn't a match for the public key the message was encrypted with."); } uncompressedMessage = AESDecryptByteArray(uncompressedMessage, aesKey); } msg.Text = System.Text.Encoding.UTF8.GetString(uncompressedMessage); return(msg); }