Example #1
0
        protected override int Decrypt(DisposeContext d, ContentType contentType, IBufferOffsetSize input, IBufferOffsetSize output)
        {
            if ((input.Size % BlockSize) != 0)
            {
                return(-1);
            }
            if (input.Size < MinExtraEncryptedBytes)
            {
                return(-1);
            }

            var plen = DecryptRecord(d, input, output);

            if (plen <= 0)
            {
                return(-1);
            }

            var padlen = output.Buffer [output.Offset + plen - 1];

                        #if DEBUG_FULL
            if (Cipher.EnableDebugging)
            {
                DebugHelper.WriteLine("DECRYPT: {0} {1} {2}", input.Size, plen, padlen);
                DebugHelper.WriteBuffer("DECRYPTED", output.Buffer, output.Offset, plen);
            }
                        #endif

            /*
             * VERY IMPORTANT:
             *
             * The Compiler and JIT *** MUST NOT *** optimize the following block of code.
             *
             * It is essential that the dummy checks and dummy calls be kept in place.
             * Also do not put any debugging code into that region as it would mess up with
             * the timing.
             *
             */

            #region The following block of code *** MUST NOT *** be optimized in any way

            if (MacSize + padlen + 1 > plen)
            {
                // Invalid padding: plaintext is not long enough.

                // First run a loop as if there were 256 bytes of padding, with a dummy check.
                int ok = -1;
                for (int i = 0; i < 256; i++)
                {
                    if (output.Buffer [i % output.Size] != padlen)
                    {
                        ok--;
                    }
                }

                // Now assume there's no padding, compute the MAC over the entire buffer.
                var first      = new BufferOffsetSize(output.Buffer, output.Offset, plen - MacSize);
                var invalidMac = ComputeRecordMAC(contentType, first);

                // Constant-time compare - this will always fail, TlsBuffer.ConstantTimeCompare() will return a negative value on error.
                ok += TlsBuffer.ConstantTimeCompare(invalidMac, 0, invalidMac.Length, output.Buffer, output.Offset + plen - MacSize, MacSize);
                return(ok);
            }
            else
            {
                int ok           = 0;
                var resultLength = plen - padlen - MacSize - 1;
                for (int i = 0; i < padlen; i++)
                {
                    if (output.Buffer [output.Offset + resultLength + MacSize + i] != padlen)
                    {
                        ok--;
                    }
                }

                var dummyOk  = ok;
                var dummyLen = 256 - padlen - 1;
                for (int i = 0; i < dummyLen; i++)
                {
                    if (output.Buffer [i % output.Size] != padlen)
                    {
                        dummyOk--;
                    }
                }

                if (ok < 0)
                {
                    // Now assume there's no padding, compute the MAC over the entire buffer.
                    var first      = new BufferOffsetSize(output.Buffer, output.Offset, plen - MacSize);
                    var invalidMac = ComputeRecordMAC(contentType, first);

                    // Constant-time compare - this will always fail, TlsBuffer.ConstantTimeCompare() will return a negative value on error.
                    ok += TlsBuffer.ConstantTimeCompare(invalidMac, 0, invalidMac.Length, output.Buffer, output.Offset + plen - MacSize, MacSize);
                    return(ok);
                }
                else
                {
                    var first    = new BufferOffsetSize(output.Buffer, output.Offset, resultLength);
                    var checkMac = ComputeRecordMAC(contentType, first);

                    var L1 = 13 + plen - MacSize;
                    var L2 = 13 + plen - padlen - 1 - MacSize;

                    var additional = ((L1 - 55) / 64) - ((L2 - 55) / 64);
                    if (additional > 0)
                    {
                        var algorithm = HMac.CreateHash(Cipher.HashAlgorithmType);
                        for (int i = 0; i < additional; i++)
                        {
                            algorithm.TransformBlock(input.Buffer, input.Offset, BlockSize, null, 0);
                        }
                    }

                    ok += TlsBuffer.ConstantTimeCompare(checkMac, 0, checkMac.Length, output.Buffer, output.Offset + resultLength, MacSize);
                    if (ok == 0)
                    {
                        ok = resultLength;
                    }
                    return(ok);
                }
            }

            #endregion
        }