private unsafe static int EncryptDecryptHelper(OP op, SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber)
{
Interop.SspiCli.SecBufferDesc sdcInOut = new Interop.SspiCli.SecBufferDesc(input.Length);
var unmanagedBuffer = new Interop.SspiCli.SecBuffer[input.Length];
fixed (Interop.SspiCli.SecBuffer* unmanagedBufferPtr = unmanagedBuffer)
{
sdcInOut.pBuffers = unmanagedBufferPtr;
GCHandle[] pinnedBuffers = new GCHandle[input.Length];
byte[][] buffers = new byte[input.Length][];
try
{
for (int i = 0; i < input.Length; i++)
{
SecurityBuffer iBuffer = input[i];
unmanagedBuffer[i].cbBuffer = iBuffer.size;
unmanagedBuffer[i].BufferType = iBuffer.type;
if (iBuffer.token == null || iBuffer.token.Length == 0)
{
unmanagedBuffer[i].pvBuffer = IntPtr.Zero;
}
else
{
pinnedBuffers[i] = GCHandle.Alloc(iBuffer.token, GCHandleType.Pinned);
unmanagedBuffer[i].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(iBuffer.token, iBuffer.offset);
buffers[i] = iBuffer.token;
}
}
// The result is written in the input Buffer passed as type=BufferType.Data.
int errorCode;
switch (op)
{
case OP.Encrypt:
errorCode = secModule.EncryptMessage(context, ref sdcInOut, sequenceNumber);
break;
case OP.Decrypt:
errorCode = secModule.DecryptMessage(context, ref sdcInOut, sequenceNumber);
break;
case OP.MakeSignature:
errorCode = secModule.MakeSignature(context, ref sdcInOut, sequenceNumber);
break;
case OP.VerifySignature:
errorCode = secModule.VerifySignature(context, ref sdcInOut, sequenceNumber);
break;
default:
NetEventSource.Fail(null, $"Unknown OP: {op}");
throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException);
}
// Marshalling back returned sizes / data.
for (int i = 0; i < input.Length; i++)
{
SecurityBuffer iBuffer = input[i];
iBuffer.size = unmanagedBuffer[i].cbBuffer;
iBuffer.type = unmanagedBuffer[i].BufferType;
if (iBuffer.size == 0)
{
iBuffer.offset = 0;
iBuffer.token = null;
}
else
{
checked
{
// Find the buffer this is inside of. Usually they all point inside buffer 0.
int j;
for (j = 0; j < input.Length; j++)
{
if (buffers[j] == null)
{
continue;
}
byte* bufferAddress = (byte*)Marshal.UnsafeAddrOfPinnedArrayElement(buffers[j], 0);
if ((byte*)unmanagedBuffer[i].pvBuffer >= bufferAddress &&
(byte*)unmanagedBuffer[i].pvBuffer + iBuffer.size <= bufferAddress + buffers[j].Length)
{
iBuffer.offset = (int)((byte*)unmanagedBuffer[i].pvBuffer - bufferAddress);
iBuffer.token = buffers[j];
break;
}
}
if (j >= input.Length)
{
NetEventSource.Fail(null, "Output buffer out of range.");
iBuffer.size = 0;
iBuffer.offset = 0;
iBuffer.token = null;
}
}
}
// Backup validate the new sizes.
if (iBuffer.offset < 0 || iBuffer.offset > (iBuffer.token == null ? 0 : iBuffer.token.Length))
{
NetEventSource.Fail(null, $"'offset' out of range. [{iBuffer.offset}]");
}
if (iBuffer.size < 0 || iBuffer.size > (iBuffer.token == null ? 0 : iBuffer.token.Length - iBuffer.offset))
{
NetEventSource.Fail(null, $"'size' out of range. [{iBuffer.size}]");
}
}
if (NetEventSource.IsEnabled && errorCode != 0)
{
if (errorCode == Interop.SspiCli.SEC_I_RENEGOTIATE)
{
NetEventSource.Error(null, SR.Format(SR.event_OperationReturnedSomething, op, "SEC_I_RENEGOTIATE"));
}
else
{
NetEventSource.Error(null, SR.Format(SR.net_log_operation_failed_with_error, op, $"0x{0:X}"));
}
}
return errorCode;
}
finally
{
for (int i = 0; i < pinnedBuffers.Length; ++i)
{
if (pinnedBuffers[i].IsAllocated)
{
pinnedBuffers[i].Free();
}
}
}
}
}