Example #1
0
        public virtual byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len)
        {
            int blocksize = encryptCipher.GetBlockSize();

            // Add a random number of extra blocks worth of padding
            int minPaddingSize       = blocksize - ((len + writeMac.Size + 1) % blocksize);
            int maxExtraPadBlocks    = (255 - minPaddingSize) / blocksize;
            int actualExtraPadBlocks = ChooseExtraPadBlocks(context.SecureRandom, maxExtraPadBlocks);
            int paddingsize          = minPaddingSize + (actualExtraPadBlocks * blocksize);

            int totalsize = len + writeMac.Size + paddingsize + 1;

            byte[] outbuf = new byte[totalsize];
            Array.Copy(plaintext, offset, outbuf, 0, len);
            byte[] mac = writeMac.CalculateMac(type, plaintext, offset, len);
            Array.Copy(mac, 0, outbuf, len, mac.Length);
            int paddoffset = len + mac.Length;

            for (int i = 0; i <= paddingsize; i++)
            {
                outbuf[i + paddoffset] = (byte)paddingsize;
            }
            for (int i = 0; i < totalsize; i += blocksize)
            {
                encryptCipher.ProcessBlock(outbuf, i, outbuf, i);
            }
            return(outbuf);
        }
Example #2
0
        public virtual byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len)
        {
            // TODO TLS 1.1 (RFC 4346) introduces an explicit IV

            int  minLength    = readMac.Size + 1;
            int  blocksize    = decryptCipher.GetBlockSize();
            bool decrypterror = false;

            /*
             * ciphertext must be at least (macsize + 1) bytes long
             */
            if (len < minLength)
            {
                throw new TlsFatalAlert(AlertDescription.decode_error);
            }

            /*
             * ciphertext must be a multiple of blocksize
             */
            if (len % blocksize != 0)
            {
                throw new TlsFatalAlert(AlertDescription.decryption_failed);
            }

            /*
             * Decrypt all the ciphertext using the blockcipher
             */
            for (int i = 0; i < len; i += blocksize)
            {
                decryptCipher.ProcessBlock(ciphertext, i + offset, ciphertext, i + offset);
            }

            /*
             * Check if padding is correct
             */
            int lastByteOffset = offset + len - 1;

            byte paddingsizebyte = ciphertext[lastByteOffset];

            int paddingsize = paddingsizebyte;

            int maxPaddingSize = len - minLength;

            if (paddingsize > maxPaddingSize)
            {
                decrypterror = true;
                paddingsize  = 0;
            }
            else
            {
                /*
                 * Now, check all the padding-bytes (constant-time comparison).
                 */
                byte diff = 0;
                for (int i = lastByteOffset - paddingsize; i < lastByteOffset; ++i)
                {
                    diff |= (byte)(ciphertext[i] ^ paddingsizebyte);
                }
                if (diff != 0)
                {
                    /* Wrong padding */
                    decrypterror = true;
                    paddingsize  = 0;
                }
            }

            /*
             * We now don't care if padding verification has failed or not, we will calculate
             * the mac to give an attacker no kind of timing profile he can use to find out if
             * mac verification failed or padding verification failed.
             */
            int plaintextlength = len - minLength - paddingsize;

            byte[] calculatedMac = readMac.CalculateMac(type, ciphertext, offset, plaintextlength);

            /*
             * Check all bytes in the mac (constant-time comparison).
             */
            byte[] decryptedMac = new byte[calculatedMac.Length];
            Array.Copy(ciphertext, offset + plaintextlength, decryptedMac, 0, calculatedMac.Length);

            if (!Arrays.ConstantTimeAreEqual(calculatedMac, decryptedMac))
            {
                decrypterror = true;
            }

            /*
             * Now, it is safe to fail.
             */
            if (decrypterror)
            {
                throw new TlsFatalAlert(AlertDescription.bad_record_mac);
            }

            byte[] plaintext = new byte[plaintextlength];
            Array.Copy(ciphertext, offset, plaintext, 0, plaintextlength);
            return(plaintext);
        }