Пример #1
0
        private static void EncryptRecord(CipherSuite cipherSuite, Record record, ICryptoTransform cipher, byte[] nonceExplicit)
        {
            BulkCipherAlgorithmType cipherType = cipherSuite.BulkCipherAlgorithm.Type;
            int recordIVLength = cipherSuite.BulkCipherAlgorithm.RecordIVLength;

            // Add explicit IV if required by protocol version
            if (cipherType == BulkCipherAlgorithmType.Block && record.Version.HasExplicitIV)
            {
                byte[] explicitIV = new byte[recordIVLength];
                RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
                rngCsp.GetBytes(explicitIV);

                // Replace the fragment with a new fragment including explicit IV
                byte[] fragment = new byte[explicitIV.Length + record.Fragment.Length];
                Buffer.BlockCopy(explicitIV, 0, fragment, 0, explicitIV.Length);
                Buffer.BlockCopy(record.Fragment, 0, fragment, explicitIV.Length, record.Fragment.Length);
                record.Fragment = fragment;
            }

            // Replace the unencrypted fragment with the encrypted fragment
            record.Fragment = TransformRecordBytes(cipherType, cipher, record.Fragment);

            // Add explicit part of the nonce if using AEAD
            if (cipherType == BulkCipherAlgorithmType.AEAD)
            {
                byte[] fragment = new byte[nonceExplicit.Length + record.Fragment.Length];
                Buffer.BlockCopy(nonceExplicit, 0, fragment, 0, nonceExplicit.Length);
                Buffer.BlockCopy(record.Fragment, 0, fragment, nonceExplicit.Length, record.Fragment.Length);
                record.Fragment = fragment;
            }
        }
Пример #2
0
        private static byte[] GenerateMAC(CipherSuite cipherSuite, Record record, UInt64 seqNum, KeyedHashAlgorithm hasher)
        {
            BulkCipherAlgorithmType cipherType = cipherSuite.BulkCipherAlgorithm.Type;

            if (cipherType == BulkCipherAlgorithmType.Stream || cipherType == BulkCipherAlgorithmType.Block)
            {
                byte[] additional = GetAdditionalBytes(seqNum, (byte)record.Type, record.Version, record.Fragment.Length);

                byte[] data = new byte[additional.Length + record.Fragment.Length];
                Buffer.BlockCopy(additional, 0, data, 0, additional.Length);
                Buffer.BlockCopy(record.Fragment, 0, data, additional.Length, record.Fragment.Length);
                Log.Trace("MAC data bytes: " + BitConverter.ToString(data));

                // Calculate the MAC of the packet
                hasher.Initialize();
                var MAC = hasher.ComputeHash(data);

                /* Add MAC to the end of the fragment */
                byte[] fragment = new byte[record.Fragment.Length + MAC.Length];
                Buffer.BlockCopy(record.Fragment, 0, fragment, 0, record.Fragment.Length);
                Buffer.BlockCopy(MAC, 0, fragment, record.Fragment.Length, MAC.Length);
                record.Fragment = fragment;

                return(MAC);
            }

            return(new byte[0]);
        }
Пример #3
0
        private static byte[] TransformRecordBytes(BulkCipherAlgorithmType cipherType, ICryptoTransform transform, byte[] input)
        {
            if (cipherType != BulkCipherAlgorithmType.AEAD)
            {
                // In case of non-AEAD cipher algorithm, check that data matches block size
                if (input.Length % transform.InputBlockSize != 0)
                {
                    throw new Exception("Input data size doesn't match block size");
                }
            }

            int blockCount = input.Length / transform.InputBlockSize;

            if (cipherType == BulkCipherAlgorithmType.AEAD)
            {
                // Make sure there is enough data at TransformFinalBlock, because
                // decryption requires that the authentication tag is present
                if (blockCount > 0)
                {
                    blockCount--;
                }
            }

            byte[] output = new byte[blockCount * transform.OutputBlockSize];
            if (transform.CanTransformMultipleBlocks)
            {
                transform.TransformBlock(input, 0, blockCount * transform.InputBlockSize, output, 0);
            }
            else
            {
                for (int i = 0; i < blockCount; i++)
                {
                    transform.TransformBlock(input, i * transform.InputBlockSize,
                                             transform.InputBlockSize,
                                             output, i * transform.OutputBlockSize);
                }
            }

            if (cipherType == BulkCipherAlgorithmType.AEAD)
            {
                int currentPosition = blockCount * transform.InputBlockSize;

                // Transfer the last block when encrypting or authentication tag when decrypting
                byte[] finalBytes = transform.TransformFinalBlock(input, currentPosition, input.Length - currentPosition);
                if (finalBytes == null)
                {
                    return(null);
                }
                else if (finalBytes.Length > 0)
                {
                    byte[] finalOutput = new byte[output.Length + finalBytes.Length];
                    Buffer.BlockCopy(output, 0, finalOutput, 0, output.Length);
                    Buffer.BlockCopy(finalBytes, 0, finalOutput, output.Length, finalBytes.Length);
                    output = finalOutput;
                }
            }

            return(output);
        }
Пример #4
0
        private static void GeneratePadding(CipherSuite cipherSuite, Record record)
        {
            BulkCipherAlgorithmType cipherType = cipherSuite.BulkCipherAlgorithm.Type;

            if (cipherType == BulkCipherAlgorithmType.Block)
            {
                int blockSize = cipherSuite.BulkCipherAlgorithm.BlockSize;

                // Add the required padding to the end of fragment if necessary,
                // minimum padding 1 bytes, the length byte of padding itself
                int paddingLength = blockSize - (record.Fragment.Length % blockSize);
                if (record.Version.HasVariablePadding)
                {
                    // Add 0-1 additional blocks
                    int extra = (new System.Random()).Next(2);
                    if (paddingLength + extra * blockSize < 256)
                    {
                        paddingLength += extra * blockSize;
                    }
                }

                // Add the actual padding bytes here
                byte[] padding = new byte[paddingLength];
                if (record.Version == ProtocolVersion.SSL3_0)
                {
                    RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
                    rngCsp.GetBytes(padding);
                    padding[padding.Length - 1] = (byte)(padding.Length - 1);
                }
                else
                {
                    for (int i = 1; i <= padding.Length; i++)
                    {
                        padding[padding.Length - i] = (byte)(padding.Length - 1);
                    }
                }

                byte[] fragment = new byte[record.Fragment.Length + padding.Length];
                Buffer.BlockCopy(record.Fragment, 0, fragment, 0, record.Fragment.Length);
                Buffer.BlockCopy(padding, 0, fragment, record.Fragment.Length, padding.Length);

                Log.Trace("Padded fragment: " + BitConverter.ToString(fragment));
                record.Fragment = fragment;
            }
        }
Пример #5
0
        private static bool RemovePadding(CipherSuite cipherSuite, Record record)
        {
            BulkCipherAlgorithmType cipherType = cipherSuite.BulkCipherAlgorithm.Type;
            bool verified = true;

            if (cipherType == BulkCipherAlgorithmType.Block)
            {
                // Get padding bytes from the end of the fragment
                int padding = record.Fragment[record.Fragment.Length - 1] + 1;

                // Verify the correctness of padding
                if (padding > record.Fragment.Length)
                {
                    verified = false;
                }
                else
                {
                    verified = true;
                    if (record.Version.HasVerifiablePadding)
                    {
                        for (int i = 1; i <= padding; i++)
                        {
                            if (record.Fragment[record.Fragment.Length - i] != (padding - 1))
                            {
                                verified = false;
                            }
                        }
                    }

                    // Remove padding from the fragment data
                    if (verified)
                    {
                        byte[] fragment = new byte[record.Fragment.Length - padding];
                        Buffer.BlockCopy(record.Fragment, 0, fragment, 0, fragment.Length);
                        record.Fragment = fragment;
                    }
                }
            }

            return(verified);
        }
Пример #6
0
        private static void GenerateMAC(CipherSuite cipherSuite, Record record, UInt64 seqNum, KeyedHashAlgorithm hasher)
        {
            BulkCipherAlgorithmType cipherType = cipherSuite.BulkCipherAlgorithm.Type;

            if (cipherType == BulkCipherAlgorithmType.Stream || cipherType == BulkCipherAlgorithmType.Block)
            {
                byte[] additional = GetAdditionalBytes(seqNum, record.Type, record.Version, record.Fragment.Length);

                // Calculate the MAC of the packet
                hasher.Initialize();
                hasher.TransformBlock(additional, 0, additional.Length, additional, 0);
                hasher.TransformFinalBlock(record.Fragment, 0, record.Fragment.Length);
                byte[] MAC = hasher.Hash;

                /* Add MAC to the end of the fragment */
                byte[] fragment = new byte[record.Fragment.Length + MAC.Length];
                Buffer.BlockCopy(record.Fragment, 0, fragment, 0, record.Fragment.Length);
                Buffer.BlockCopy(MAC, 0, fragment, record.Fragment.Length, MAC.Length);
                record.Fragment = fragment;
            }
        }
Пример #7
0
        private static bool RemoveMAC(CipherSuite cipherSuite, Record record, UInt64 seqNum, KeyedHashAlgorithm hasher)
        {
            BulkCipherAlgorithmType cipherType = cipherSuite.BulkCipherAlgorithm.Type;
            bool verified = true;

            if (cipherType == BulkCipherAlgorithmType.Stream || cipherType == BulkCipherAlgorithmType.Block)
            {
                int MACLength = cipherSuite.MACAlgorithm.HashSize;
                if (record.Fragment.Length < MACLength)
                {
                    verified = false;
                }
                else
                {
                    // Allocate a fragment without the MAC value
                    byte[] newFragment = new byte[record.Fragment.Length - MACLength];
                    Buffer.BlockCopy(record.Fragment, 0, newFragment, 0, newFragment.Length);

                    // Calculate the MAC again for new fragment
                    byte[] oldFragment = record.Fragment;
                    record.Fragment = newFragment;
                    GenerateMAC(cipherSuite, record, seqNum, hasher);

                    // Compare our MAC value with theirs
                    verified = true;
                    for (int i = 1; i <= MACLength; i++)
                    {
                        if (oldFragment[oldFragment.Length - i] != record.Fragment[record.Fragment.Length - i])
                        {
                            verified = false;
                        }
                    }

                    // Replace fragment with the one without MAC value
                    record.Fragment = newFragment;
                }
            }

            return(verified);
        }
Пример #8
0
        private static bool DecryptRecord(CipherSuite cipherSuite, Record record, ICryptoTransform cipher)
        {
            BulkCipherAlgorithmType cipherType = cipherSuite.BulkCipherAlgorithm.Type;
            int recordIVLength = cipherSuite.BulkCipherAlgorithm.RecordIVLength;

            if (cipherType == BulkCipherAlgorithmType.AEAD)
            {
                int authTagSize = cipherSuite.BulkCipherAlgorithm.AuthenticationTagSize;

                // Remove explicit nonce from the beginning of the fragment
                byte[] tmp = new byte[record.Fragment.Length - recordIVLength];
                Buffer.BlockCopy(record.Fragment, recordIVLength, tmp, 0, tmp.Length);
                record.Fragment = tmp;

                // Make sure there is enough data for the authentication tag
                if (record.Fragment.Length < authTagSize)
                {
                    return(false);
                }
            }

            // Replace the encrypted fragment with the decrypted fragment
            byte[] fragment = TransformRecordBytes(cipherType, cipher, record.Fragment);
            if (fragment == null)
            {
                return(false);
            }
            record.Fragment = fragment;

            // Remove explicit IV from the beginning of the fragment if necessary
            if (cipherType == BulkCipherAlgorithmType.Block && record.Version.HasExplicitIV)
            {
                fragment = new byte[record.Fragment.Length - recordIVLength];
                Buffer.BlockCopy(record.Fragment, recordIVLength, fragment, 0, record.Fragment.Length - recordIVLength);
                record.Fragment = fragment;
            }

            return(true);
        }
Пример #9
0
        private static byte[] TransformRecordBytes(BulkCipherAlgorithmType cipherType, ICryptoTransform transform, byte[] input)
        {
            if (cipherType != BulkCipherAlgorithmType.AEAD) {
                // In case of non-AEAD cipher algorithm, check that data matches block size
                if (input.Length % transform.InputBlockSize != 0) {
                    throw new Exception("Input data size doesn't match block size");
                }
            }

            int blockCount = input.Length / transform.InputBlockSize;
            if (cipherType == BulkCipherAlgorithmType.AEAD) {
                // Make sure there is enough data at TransformFinalBlock, because
                // decryption requires that the authentication tag is present
                if (blockCount > 0) {
                    blockCount--;
                }
            }

            byte[] output = new byte[blockCount * transform.OutputBlockSize];
            if (transform.CanTransformMultipleBlocks) {
                transform.TransformBlock(input, 0, blockCount*transform.InputBlockSize, output, 0);
            } else {
                for (int i=0; i<blockCount; i++) {
                    transform.TransformBlock(input, i*transform.InputBlockSize,
                                             transform.InputBlockSize,
                                             output, i*transform.OutputBlockSize);
                }
            }

            if (cipherType == BulkCipherAlgorithmType.AEAD) {
                int currentPosition = blockCount*transform.InputBlockSize;

                // Transfer the last block when encrypting or authentication tag when decrypting
                byte[] finalBytes = transform.TransformFinalBlock(input, currentPosition, input.Length-currentPosition);
                if (finalBytes == null) {
                    return null;
                } else if (finalBytes.Length > 0) {
                    byte[] finalOutput = new byte[output.Length + finalBytes.Length];
                    Buffer.BlockCopy(output, 0, finalOutput, 0, output.Length);
                    Buffer.BlockCopy(finalBytes, 0, finalOutput, output.Length, finalBytes.Length);
                    output = finalOutput;
                }
            }

            return output;
        }