package org.bouncycastle.crypto.tls;

import java.io.IOException;

import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.StreamCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.Arrays;

public class TlsStreamCipher implements TlsCipher
{
    protected TlsContext context;

    protected StreamCipher encryptCipher;
    protected StreamCipher decryptCipher;

    protected TlsMac writeMac;
    protected TlsMac readMac;

    public TlsStreamCipher(TlsContext context, StreamCipher encryptCipher,
        StreamCipher decryptCipher, Digest writeDigest, Digest readDigest, int cipherKeySize)
        throws IOException
    {
        this.context = context;
        this.encryptCipher = encryptCipher;
        this.decryptCipher = decryptCipher;

        int prfSize = (2 * cipherKeySize) + writeDigest.getDigestSize()
            + readDigest.getDigestSize();

        SecurityParameters securityParameters = context.getSecurityParameters();

        byte[] keyBlock = TlsUtils.PRF(securityParameters.masterSecret, "key expansion",
            TlsUtils.concat(securityParameters.serverRandom, securityParameters.clientRandom),
            prfSize);

        int offset = 0;

        // Init MACs
        writeMac = new TlsMac(context, writeDigest, keyBlock, offset, writeDigest.getDigestSize());
        offset += writeDigest.getDigestSize();
        readMac = new TlsMac(context, readDigest, keyBlock, offset, readDigest.getDigestSize());
        offset += readDigest.getDigestSize();

        // Build keys
        KeyParameter encryptKey = new KeyParameter(keyBlock, offset, cipherKeySize);
        offset += cipherKeySize;
        KeyParameter decryptKey = new KeyParameter(keyBlock, offset, cipherKeySize);
        offset += cipherKeySize;

        if (offset != prfSize)
        {
            throw new TlsFatalAlert(AlertDescription.internal_error);
        }

        encryptCipher.init(true, encryptKey);
        decryptCipher.init(true, decryptKey);
    }

    public int getPlaintextLimit(int ciphertextLimit)
    {
        return ciphertextLimit - writeMac.getSize();
    }

    public byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len)
    {
        byte[] mac = writeMac.calculateMac(seqNo, type, plaintext, offset, len);

        byte[] outbuf = new byte[len + mac.length];

        encryptCipher.processBytes(plaintext, offset, len, outbuf, 0);
        encryptCipher.processBytes(mac, 0, mac.length, outbuf, len);

        return outbuf;
    }

    public byte[] decodeCiphertext(long seqNo, short type, byte[] ciphertext, int offset, int len)
        throws IOException
    {
        byte[] deciphered = new byte[len];
        decryptCipher.processBytes(ciphertext, offset, len, deciphered, 0);

        int plaintextSize = deciphered.length - readMac.getSize();
        byte[] plainText = copyData(deciphered, 0, plaintextSize);

        byte[] receivedMac = copyData(deciphered, plaintextSize, readMac.getSize());
        byte[] computedMac = readMac.calculateMac(seqNo, type, plainText, 0, plainText.length);

        if (!Arrays.constantTimeAreEqual(receivedMac, computedMac))
        {
            throw new TlsFatalAlert(AlertDescription.bad_record_mac);
        }

        return plainText;
    }

    protected byte[] copyData(byte[] text, int offset, int len)
    {
        byte[] result = new byte[len];
        System.arraycopy(text, offset, result, 0, len);
        return result;
    }
}

@@ -722,24 +722,26 @@
 = context;%0D%0A
+%0D%0A
         this
@@ -832,20 +832,27 @@
     int 
-prfS
+key_block_s
 ize = (2
@@ -949,92 +949,8 @@
 %0D%0A%0D%0A
-        SecurityParameters securityParameters = context.getSecurityParameters();%0D%0A%0D%0A
     
@@ -959,25 +959,26 @@
   byte%5B%5D key
-B
+_b
 lock = TlsUt
@@ -985,175 +985,46 @@
 ils.
-PRF(securityParameters.masterSecret, %22key expansion%22,%0D%0A            TlsUtils.concat(securityParameters.serverRandom, securityParameters.clientRandom),%0D%0A            prfS
+calculateKeyBlock(context, key_block_s
 ize)
@@ -1124,33 +1124,34 @@
 writeDigest, key
-B
+_b
 lock, offset, wr
@@ -1280,17 +1280,18 @@
 est, key
-B
+_b
 lock, of
@@ -1444,33 +1444,34 @@
 KeyParameter(key
-B
+_b
 lock, offset, ci
@@ -1573,17 +1573,18 @@
 eter(key
-B
+_b
 lock, of
@@ -1668,12 +1668,19 @@
  != 
-prfS
+key_block_s
 ize)
@@ -1850,19 +1850,20 @@
 er.init(
-tru
+fals
 e, decry

Use utility method to calculate key_block