internal static int Encrypt(
SafeDeleteContext securityContext,
byte[] buffer,
int offset,
int count,
bool isConfidential,
bool isNtlm,
ref byte[] output,
uint sequenceNumber)
{
SecPkgContext_Sizes sizes = SSPIWrapper.QueryContextAttributes(
GlobalSSPI.SSPIAuth,
securityContext,
Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SIZES
) as SecPkgContext_Sizes;
try
{
int maxCount = checked(Int32.MaxValue - 4 - sizes.cbBlockSize - sizes.cbSecurityTrailer);
if (count > maxCount || count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.net_io_out_range, maxCount));
}
}
catch (Exception e) when (!ExceptionCheck.IsFatal(e))
{
NetEventSource.Fail(null, "Arguments out of range.");
throw;
}
int resultSize = count + sizes.cbSecurityTrailer + sizes.cbBlockSize;
if (output == null || output.Length < resultSize + 4)
{
output = new byte[resultSize + 4];
}
// Make a copy of user data for in-place encryption.
Buffer.BlockCopy(buffer, offset, output, 4 + sizes.cbSecurityTrailer, count);
// Prepare buffers TOKEN(signature), DATA and Padding.
var securityBuffer = new SecurityBuffer[3];
securityBuffer[0] = new SecurityBuffer(output, 4, sizes.cbSecurityTrailer, SecurityBufferType.SECBUFFER_TOKEN);
securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer, count, SecurityBufferType.SECBUFFER_DATA);
securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer + count, sizes.cbBlockSize, SecurityBufferType.SECBUFFER_PADDING);
int errorCode;
if (isConfidential)
{
errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber);
}
else
{
if (isNtlm)
{
securityBuffer[1].type |= SecurityBufferType.SECBUFFER_READONLY;
}
errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, 0);
}
if (errorCode != 0)
{
Exception e = new Win32Exception(errorCode);
if (NetEventSource.IsEnabled) NetEventSource.Error(null, e);
throw e;
}
// Compacting the result.
resultSize = securityBuffer[0].size;
bool forceCopy = false;
if (resultSize != sizes.cbSecurityTrailer)
{
forceCopy = true;
Buffer.BlockCopy(output, securityBuffer[1].offset, output, 4 + resultSize, securityBuffer[1].size);
}
resultSize += securityBuffer[1].size;
if (securityBuffer[2].size != 0 && (forceCopy || resultSize != (count + sizes.cbSecurityTrailer)))
{
Buffer.BlockCopy(output, securityBuffer[2].offset, output, 4 + resultSize, securityBuffer[2].size);
}
resultSize += securityBuffer[2].size;
unchecked
{
output[0] = (byte)((resultSize) & 0xFF);
output[1] = (byte)(((resultSize) >> 8) & 0xFF);
output[2] = (byte)(((resultSize) >> 16) & 0xFF);
output[3] = (byte)(((resultSize) >> 24) & 0xFF);
}
return resultSize + 4;
}