53 lines
2.1 KiB
C#
53 lines
2.1 KiB
C#
namespace DataTransfer.Client.Services;
|
|
|
|
/// <summary>
|
|
/// Plaintext messages of the commit-then-reveal key exchange (see <see cref="SecureChannel" />). They are relayed
|
|
/// like frames, but before the channel is encrypted. Layout: version (byte) | type (byte) | payload.
|
|
/// </summary>
|
|
internal static class HandshakeCodec
|
|
{
|
|
public const int CommitmentBytes = 32;
|
|
|
|
// A P-256 SPKI key has 91 bytes; anything much larger is not a key.
|
|
private const int MaxPublicKeyBytes = 512;
|
|
private const byte Version = 1;
|
|
|
|
private enum MessageType : byte
|
|
{
|
|
Commitment = 1,
|
|
PublicKey = 2
|
|
}
|
|
|
|
public static byte[] EncodeCommitment(byte[] commitment) => Encode(MessageType.Commitment, commitment);
|
|
|
|
public static byte[] EncodePublicKey(byte[] publicKey) => Encode(MessageType.PublicKey, publicKey);
|
|
|
|
/// <exception cref="InvalidDataException">The message is not a commitment.</exception>
|
|
public static byte[] DecodeCommitment(byte[] message) =>
|
|
Decode(message, MessageType.Commitment, CommitmentBytes, CommitmentBytes);
|
|
|
|
/// <exception cref="InvalidDataException">The message is not a public key.</exception>
|
|
public static byte[] DecodePublicKey(byte[] message) => Decode(message, MessageType.PublicKey, 1, MaxPublicKeyBytes);
|
|
|
|
private static byte[] Encode(MessageType type, byte[] payload)
|
|
{
|
|
var message = new byte[payload.Length + 2];
|
|
message[0] = Version;
|
|
message[1] = (byte)type;
|
|
payload.CopyTo(message, 2);
|
|
return message;
|
|
}
|
|
|
|
private static byte[] Decode(byte[] message, MessageType type, int minPayloadBytes, int maxPayloadBytes)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(message);
|
|
|
|
var payloadBytes = message.Length - 2;
|
|
if (payloadBytes < minPayloadBytes || payloadBytes > maxPayloadBytes || message[0] != Version || message[1] != (byte)type)
|
|
{
|
|
throw new InvalidDataException($"Expected a valid key-exchange message of type {type}.");
|
|
}
|
|
|
|
return message[2..];
|
|
}
|
|
}
|