3using Microsoft.Extensions.Logging;
34 Logger = loggerFactory?.CreateLogger(GetType());
66 public abstract void EncodePayload(
byte[] payload, Span<byte> destination);
69 public abstract ReadOnlySpan<byte>
GenerateMac(ReadOnlySpan<byte> message,
bool isIncoming);
72 public void InitializeACU(
byte[] clientRandomNumber,
byte[] clientCryptogram)
74 Context.InitializeACU(clientRandomNumber, clientCryptogram);
99 private byte[]
GenerateMac(ReadOnlySpan<byte> message,
byte[] iv)
103 throw new SecureChannelRequired();
109 var cursor = message;
110 while (cursor.Length > 0)
114 if (cursor.Length < 16)
116 block =
new byte[16];
117 cursor.CopyTo(block);
119 cursor = cursor.Slice(cursor.Length);
124 block = cursor.Slice(0, 16).ToArray();
125 cursor = cursor.Slice(16);
126 if (cursor.Length == 0) crypto.Key =
Context.SMac2;
129 using var encryptor = crypto.CreateEncryptor();
130 crypto.IV = encryptor.TransformFinalBlock(block, 0, block.Length);
146 throw new SecureChannelRequired();
149 if (payload.Length == 0)
151 return Array.Empty<
byte>();
153 if (payload.Length % 16 != 0)
155 throw new Exception($
"Unexpected payload length: {payload.Length}");
159 crypto.IV = iv.Select(b => (
byte)~b).ToArray();
161 using var encryptor = crypto.CreateDecryptor();
162 return encryptor.TransformFinalBlock(payload, 0, payload.Length);
172 protected void EncodePayload(
byte[] payload,
byte[] iv, Span<byte> destination)
176 throw new SecureChannelRequired();
179 if (payload.Length > 0)
181 if (payload.Length % 16 != 0)
183 throw new Exception($
"Unexpected payload length: {payload.Length}");
187 crypto.IV = iv.Select(b => (
byte)~b).ToArray();
189 using var encryptor = crypto.CreateEncryptor();
190 encryptor.TransformFinalBlock(payload, 0, payload.Length).CopyTo(destination);
195 public ReadOnlySpan<byte>
PadTheData(ReadOnlySpan<byte> data)
197 const byte cryptoLength = 16;
198 const byte paddingStart = 0x80;
200 int dataLength = data.Length + 1;
201 int paddingLength = dataLength + (cryptoLength - dataLength % cryptoLength) % cryptoLength;
203 Span<byte> buffer = stackalloc
byte[paddingLength];
206 var cursor = buffer.Slice(0);
209 cursor = cursor.Slice(data.Length);
211 cursor[0] = paddingStart;
213 return buffer.ToArray();
A base message class for sending or replying.
const byte FirstPaddingByte
While padding bytes are generally 0x00, the first byte of padding is not.
byte[] DecodePayload(byte[] payload, byte[] iv)
Decodes the payload.
byte[] GenerateCommandMac(ReadOnlySpan< byte > message)
Generates a MAC for a command message.
bool IsSecurityEstablished
Indicates whether or not a secure channel has been established on the current message channel.
byte[] GenerateReplyMac(ReadOnlySpan< byte > message)
Generates a MAC for a reply message.
void Establish(byte[] rmac)
Establishes the secure channel with the provided RMAC.
void ResetSecureChannelSession()
Resets the secure channel session by creating a new random number.
ILogger Logger
Optional logger instance.
bool IsUsingDefaultKey
Gets a value indicating whether the secure channel is using the default key.
byte[] ServerRandomNumber
Represents the server random number used in the secure channel context.
void EncodePayload(byte[] payload, Span< byte > destination)
Encrypts the payload using the secure channel context.This function can only be called once IsSecurit...
ReadOnlySpan< byte > PadTheData(ReadOnlySpan< byte > data)
Pads the given data with padding bytes to make it a multiple of a specified length....
void EncodePayload(byte[] payload, byte[] iv, Span< byte > destination)
Encodes the payload.
ReadOnlySpan< byte > GenerateMac(ReadOnlySpan< byte > message, bool isIncoming)
Generates a new Message Authentication Code.Note this command IS NOT idempotent as every time it is c...
MessageSecureChannel(SecurityContext context=null, ILoggerFactory loggerFactory=null)
Initializes a new instance of MessageSecureChannel class.
byte[] ServerCryptogram
Represents the secure channel cryptogram used by the server.This property is used to retrieve the ser...
bool IsInitialized
Gets a value indicating whether the secure channel is initialized.true if the secure channel is initi...
SecurityContext Context
Security state used by the channel.
byte[] DecodePayload(byte[] payload)
Decodes the payload using the secure channel context.This function can only be called once IsSecurity...
void InitializeACU(byte[] clientRandomNumber, byte[] clientCryptogram)
Initializes the Access Control Unit (ACU) in the secure channel context.
Security context used within MessageSecureChannel.
Represents the secure channel context within which a message is packed/unpacked.