Exemple #1
0
        /// <summary>
        /// Signs the message using the context's session key.
        /// </summary>
        /// <remarks>
        /// The structure of the returned buffer is as follows:
        ///  - 4 bytes, unsigned big-endian integer indicating the length of the plaintext message
        ///  - 2 bytes, unsigned big-endian integer indicating the length of the signture
        ///  - The plaintext message
        ///  - The message's signature.
        /// </remarks>
        /// <param name="message"></param>
        /// <returns></returns>
        public byte[] MakeSignature(byte[] message)
        {
            CSecurityStatus status = CSecurityStatus.InternalError;

            CSecPkgContext_Sizes sizes;
            CSecureBuffer        dataBuffer;
            CSecureBuffer        signatureBuffer;
            CSecureBufferAdapter adapter;

            CheckLifecycle();

            sizes = QueryBufferSizes();

            dataBuffer      = new CSecureBuffer(new byte[message.Length], CBufferType.Data);
            signatureBuffer = new CSecureBuffer(new byte[sizes.MaxSignature], CBufferType.Token);

            Array.Copy(message, dataBuffer.Buffer, message.Length);

            using (adapter = new CSecureBufferAdapter(new[] { dataBuffer, signatureBuffer }))
            {
                status = CContextNativeMethods.SafeMakeSignature(
                    this.ContextHandle,
                    0,
                    adapter,
                    0
                    );
            }

            if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to create message signature.", status);
            }

            byte[] outMessage;
            int    position = 0;

            // Enough room for
            //  - original message length (4 bytes)
            //  - signature length        (2 bytes)
            //  - original message
            //  - signature

            outMessage = new byte[4 + 2 + dataBuffer.Length + signatureBuffer.Length];

            CByteWriter.WriteInt32_BE(dataBuffer.Length, outMessage, position);
            position += 4;

            CByteWriter.WriteInt16_BE((Int16)signatureBuffer.Length, outMessage, position);
            position += 2;

            Array.Copy(dataBuffer.Buffer, 0, outMessage, position, dataBuffer.Length);
            position += dataBuffer.Length;

            Array.Copy(signatureBuffer.Buffer, 0, outMessage, position, signatureBuffer.Length);
            position += signatureBuffer.Length;

            return(outMessage);
        }
Exemple #2
0
        /// <summary>
        /// Verifies the signature of a signed message
        /// </summary>
        /// <remarks>
        /// The expected structure of the signed message buffer is as follows:
        ///  - 4 bytes, unsigned integer in big endian format indicating the length of the plaintext message
        ///  - 2 bytes, unsigned integer in big endian format indicating the length of the signture
        ///  - The plaintext message
        ///  - The message's signature.
        /// </remarks>
        /// <param name="signedMessage">The packed signed message.</param>
        /// <param name="origMessage">The extracted original message.</param>
        /// <returns>True if the message has a valid signature, false otherwise.</returns>
        public bool VerifySignature(byte[] signedMessage, out byte[] origMessage)
        {
            CSecurityStatus status = CSecurityStatus.InternalError;

            CSecPkgContext_Sizes sizes;
            CSecureBuffer        dataBuffer;
            CSecureBuffer        signatureBuffer;
            CSecureBufferAdapter adapter;

            CheckLifecycle();

            sizes = QueryBufferSizes();

            if (signedMessage.Length < 2 + 4 + sizes.MaxSignature)
            {
                throw new ArgumentException("Input message is too small to possibly fit a valid message");
            }

            int position = 0;
            int messageLen;
            int sigLen;

            messageLen = CByteWriter.ReadInt32_BE(signedMessage, 0);
            position  += 4;

            sigLen    = CByteWriter.ReadInt16_BE(signedMessage, position);
            position += 2;

            if (messageLen + sigLen + 2 + 4 > signedMessage.Length)
            {
                throw new ArgumentException("The buffer contains invalid data - the embedded length data does not add up.");
            }

            dataBuffer = new CSecureBuffer(new byte[messageLen], CBufferType.Data);
            Array.Copy(signedMessage, position, dataBuffer.Buffer, 0, messageLen);
            position += messageLen;

            signatureBuffer = new CSecureBuffer(new byte[sigLen], CBufferType.Token);
            Array.Copy(signedMessage, position, signatureBuffer.Buffer, 0, sigLen);
            position += sigLen;

            using (adapter = new CSecureBufferAdapter(new[] { dataBuffer, signatureBuffer }))
            {
                status = CContextNativeMethods.SafeVerifySignature(
                    this.ContextHandle,
                    0,
                    adapter,
                    0
                    );
            }

            if (status == CSecurityStatus.OK)
            {
                origMessage = dataBuffer.Buffer;
                return(true);
            }
            else if (status == CSecurityStatus.MessageAltered ||
                     status == CSecurityStatus.OutOfSequence)
            {
                origMessage = null;
                return(false);
            }
            else
            {
                throw new CSSPIException("Failed to determine the veracity of a signed message.", status);
            }
        }
Exemple #3
0
        /// <summary>
        /// Decrypts a previously encrypted message.
        /// </summary>
        /// <remarks>
        /// The expected format of the buffer is as follows:
        ///  - 2 bytes, an unsigned big-endian integer indicating the length of the trailer buffer size
        ///  - 4 bytes, an unsigned big-endian integer indicating the length of the message buffer size.
        ///  - 2 bytes, an unsigned big-endian integer indicating the length of the encryption padding buffer size.
        ///  - The trailer buffer
        ///  - The message buffer
        ///  - The padding buffer.
        /// </remarks>
        /// <param name="input">The packed and encrypted data.</param>
        /// <returns>The original plaintext message.</returns>
        public byte[] Decrypt(byte[] input)
        {
            CSecPkgContext_Sizes sizes;

            CSecureBuffer        trailerBuffer;
            CSecureBuffer        dataBuffer;
            CSecureBuffer        paddingBuffer;
            CSecureBufferAdapter adapter;

            CSecurityStatus status;

            byte[] result = null;
            int    remaining;
            int    position;

            int trailerLength;
            int dataLength;
            int paddingLength;

            CheckLifecycle();

            sizes = QueryBufferSizes();

            // This check is required, but not sufficient. We could be stricter.
            if (input.Length < 2 + 4 + 2 + sizes.SecurityTrailer)
            {
                throw new ArgumentException("Buffer is too small to possibly contain an encrypted message");
            }

            position = 0;

            trailerLength = CByteWriter.ReadInt16_BE(input, position);
            position     += 2;

            dataLength = CByteWriter.ReadInt32_BE(input, position);
            position  += 4;

            paddingLength = CByteWriter.ReadInt16_BE(input, position);
            position     += 2;

            if (trailerLength + dataLength + paddingLength + 2 + 4 + 2 > input.Length)
            {
                throw new ArgumentException("The buffer contains invalid data - the embedded length data does not add up.");
            }

            trailerBuffer = new CSecureBuffer(new byte[trailerLength], CBufferType.Token);
            dataBuffer    = new CSecureBuffer(new byte[dataLength], CBufferType.Data);
            paddingBuffer = new CSecureBuffer(new byte[paddingLength], CBufferType.Padding);

            remaining = input.Length - position;

            if (trailerBuffer.Length <= remaining)
            {
                Array.Copy(input, position, trailerBuffer.Buffer, 0, trailerBuffer.Length);
                position  += trailerBuffer.Length;
                remaining -= trailerBuffer.Length;
            }
            else
            {
                throw new ArgumentException("Input is missing data - it is not long enough to contain a fully encrypted message");
            }

            if (dataBuffer.Length <= remaining)
            {
                Array.Copy(input, position, dataBuffer.Buffer, 0, dataBuffer.Length);
                position  += dataBuffer.Length;
                remaining -= dataBuffer.Length;
            }
            else
            {
                throw new ArgumentException("Input is missing data - it is not long enough to contain a fully encrypted message");
            }

            if (paddingBuffer.Length <= remaining)
            {
                Array.Copy(input, position, paddingBuffer.Buffer, 0, paddingBuffer.Length);
            }
            // else there was no padding.


            using (adapter = new CSecureBufferAdapter(new [] { trailerBuffer, dataBuffer, paddingBuffer }))
            {
                status = CContextNativeMethods.SafeDecryptMessage(
                    this.ContextHandle,
                    0,
                    adapter,
                    0
                    );
            }

            if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to encrypt message", status);
            }

            result = new byte[dataBuffer.Length];
            Array.Copy(dataBuffer.Buffer, 0, result, 0, dataBuffer.Length);

            return(result);
        }
Exemple #4
0
        /// <summary>
        /// Encrypts the byte array using the context's session key.
        /// </summary>
        /// <remarks>
        /// The structure of the returned data is as follows:
        ///  - 2 bytes, an unsigned big-endian integer indicating the length of the trailer buffer size
        ///  - 4 bytes, an unsigned big-endian integer indicating the length of the message buffer size.
        ///  - 2 bytes, an unsigned big-endian integer indicating the length of the encryption padding buffer size.
        ///  - The trailer buffer
        ///  - The message buffer
        ///  - The padding buffer.
        /// </remarks>
        /// <param name="input">The raw message to encrypt.</param>
        /// <returns>The packed and encrypted message.</returns>
        public byte[] Encrypt(byte[] input)
        {
            // The message is encrypted in place in the buffer we provide to Win32 EncryptMessage
            CSecPkgContext_Sizes sizes;

            CSecureBuffer        trailerBuffer;
            CSecureBuffer        dataBuffer;
            CSecureBuffer        paddingBuffer;
            CSecureBufferAdapter adapter;

            CSecurityStatus status = CSecurityStatus.InvalidHandle;

            byte[] result;

            CheckLifecycle();

            sizes = QueryBufferSizes();

            trailerBuffer = new CSecureBuffer(new byte[sizes.SecurityTrailer], CBufferType.Token);
            dataBuffer    = new CSecureBuffer(new byte[input.Length], CBufferType.Data);
            paddingBuffer = new CSecureBuffer(new byte[sizes.BlockSize], CBufferType.Padding);

            Array.Copy(input, dataBuffer.Buffer, input.Length);

            using (adapter = new CSecureBufferAdapter(new[] { trailerBuffer, dataBuffer, paddingBuffer }))
            {
                status = CContextNativeMethods.SafeEncryptMessage(
                    this.ContextHandle,
                    0,
                    adapter,
                    0
                    );
            }

            if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to encrypt message", status);
            }

            int position = 0;

            // Enough room to fit:
            //  -- 2 bytes for the trailer buffer size
            //  -- 4 bytes for the message size
            //  -- 2 bytes for the padding size.
            //  -- The encrypted message
            result = new byte[2 + 4 + 2 + trailerBuffer.Length + dataBuffer.Length + paddingBuffer.Length];

            CByteWriter.WriteInt16_BE((short)trailerBuffer.Length, result, position);
            position += 2;

            CByteWriter.WriteInt32_BE(dataBuffer.Length, result, position);
            position += 4;

            CByteWriter.WriteInt16_BE((short)paddingBuffer.Length, result, position);
            position += 2;

            Array.Copy(trailerBuffer.Buffer, 0, result, position, trailerBuffer.Length);
            position += trailerBuffer.Length;

            Array.Copy(dataBuffer.Buffer, 0, result, position, dataBuffer.Length);
            position += dataBuffer.Length;

            Array.Copy(paddingBuffer.Buffer, 0, result, position, paddingBuffer.Length);
            position += paddingBuffer.Length;

            return(result);
        }