60 lines
2.3 KiB
C#
60 lines
2.3 KiB
C#
using Sodium;
|
|
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using XIVChatCommon.Message;
|
|
|
|
namespace XIVChatCommon {
|
|
public static class SecretMessage {
|
|
private const uint MaxMessageLen = 128_000;
|
|
|
|
public static async Task<byte[]> ReadSecretMessage(Stream s, byte[] key, CancellationToken token = default) {
|
|
var read = 0;
|
|
|
|
byte[] header = new byte[4 + 24];
|
|
while (read < header.Length) {
|
|
read += await s.ReadAsync(header, read, header.Length - read, token);
|
|
}
|
|
|
|
var length = BitConverter.ToUInt32(header, 0);
|
|
byte[] nonce = header.Skip(4).ToArray();
|
|
|
|
if (length > MaxMessageLen) {
|
|
throw new ArgumentOutOfRangeException($"Encrypted message specified a size of {length}, which is greater than the limit of {MaxMessageLen}");
|
|
}
|
|
|
|
byte[] ciphertext = new byte[length];
|
|
read = 0;
|
|
while (read < ciphertext.Length) {
|
|
read += await s.ReadAsync(ciphertext, read, ciphertext.Length - read, token);
|
|
}
|
|
|
|
return SecretBox.Open(ciphertext, nonce, key);
|
|
}
|
|
|
|
public static async Task SendSecretMessage(Stream s, byte[] key, byte[] message, CancellationToken token = default) {
|
|
byte[] nonce = SecretBox.GenerateNonce();
|
|
byte[] ciphertext = SecretBox.Create(message, nonce, key);
|
|
byte[] len = BitConverter.GetBytes((uint)ciphertext.Length);
|
|
|
|
if (ciphertext.Length > MaxMessageLen) {
|
|
throw new ArgumentOutOfRangeException($"Encrypted message would be {len} bytes long, which is larger than the limit of {MaxMessageLen}");
|
|
}
|
|
|
|
await s.WriteAsync(len, 0, len.Length, token);
|
|
await s.WriteAsync(nonce, 0, nonce.Length, token);
|
|
await s.WriteAsync(ciphertext, 0, ciphertext.Length, token);
|
|
await s.FlushAsync(token);
|
|
}
|
|
|
|
public static async Task SendSecretMessage(Stream s, byte[] key, Encodable message, CancellationToken token = default) {
|
|
await SendSecretMessage(s, key, message.Encode(), token);
|
|
}
|
|
|
|
public const int MacSize = 16;
|
|
public const int NonceSize = 24;
|
|
}
|
|
}
|