<commit_before>package org.bouncycastle.tls.crypto.impl;

import java.io.IOException;
import java.security.SecureRandom;

import org.bouncycastle.tls.AlertDescription;
import org.bouncycastle.tls.TlsFatalAlert;
import org.bouncycastle.tls.crypto.TlsCipher;
import org.bouncycastle.tls.crypto.TlsCrypto;
import org.bouncycastle.tls.crypto.TlsCryptoParameters;
import org.bouncycastle.tls.crypto.TlsHMAC;
import org.bouncycastle.util.Arrays;

/**
 * A generic TLS 1.0-1.2 block cipher. This can be used for AES or 3DES for example.
 */
public class TlsBlockCipher
    implements TlsCipher
{
    protected final TlsCrypto crypto;
    protected final TlsCryptoParameters cryptoParams;
    protected final byte[] randomData;
    protected final boolean encryptThenMAC;
    protected final boolean useExplicitIV;
    protected final boolean useExtraPadding;

    protected final TlsBlockCipherImpl decryptCipher, encryptCipher;
    protected final TlsSuiteMac readMac, writeMac;

    public TlsBlockCipher(TlsCrypto crypto, TlsCryptoParameters cryptoParams, TlsBlockCipherImpl encryptCipher,
        TlsBlockCipherImpl decryptCipher, TlsHMAC clientMac, TlsHMAC serverMac, int cipherKeySize) throws IOException
    {
        this.cryptoParams = cryptoParams;
        this.crypto = crypto;
        this.randomData = cryptoParams.getNonceGenerator().generateNonce(256);

        this.encryptThenMAC = cryptoParams.getSecurityParameters().isEncryptThenMAC();
        this.useExplicitIV = TlsImplUtils.isTLSv11(cryptoParams);

        /*
         * Don't use variable-length padding with truncated MACs.
         * 
         * See "Tag Size Does Matter: Attacks and Proofs for the TLS Record Protocol", Paterson,
         * Ristenpart, Shrimpton.
         *
         * TODO[DTLS] Consider supporting in DTLS (without exceeding send limit though)
         */
        this.useExtraPadding = !cryptoParams.getServerVersion().isDTLS()
            && (encryptThenMAC || !cryptoParams.getSecurityParameters().isTruncatedHMac());

        this.encryptCipher = encryptCipher;
        this.decryptCipher = decryptCipher;

        TlsBlockCipherImpl clientCipher, serverCipher;
        if (cryptoParams.isServer())
        {
            clientCipher = decryptCipher;
            serverCipher = encryptCipher;
        }
        else
        {
            clientCipher = encryptCipher;
            serverCipher = decryptCipher;
        }

        int key_block_size = (2 * cipherKeySize) + clientMac.getMacLength() + serverMac.getMacLength();

        // From TLS 1.1 onwards, block ciphers don't need IVs from the key_block
        if (!useExplicitIV)
        {
            key_block_size += clientCipher.getBlockSize() + serverCipher.getBlockSize();
        }

        byte[] key_block = TlsImplUtils.calculateKeyBlock(cryptoParams, key_block_size);

        int offset = 0;

        clientMac.setKey(key_block, offset, clientMac.getMacLength());
        offset += clientMac.getMacLength();
        serverMac.setKey(key_block, offset, serverMac.getMacLength());
        offset += serverMac.getMacLength();

        clientCipher.setKey(key_block, offset, cipherKeySize);
        offset += cipherKeySize;
        serverCipher.setKey(key_block, offset, cipherKeySize);
        offset += cipherKeySize;

        if (!useExplicitIV)
        {
            clientCipher.init(key_block, offset, clientCipher.getBlockSize());
            offset += clientCipher.getBlockSize();
            serverCipher.init(key_block, offset, serverCipher.getBlockSize());
            offset += serverCipher.getBlockSize();
        }

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

        if (cryptoParams.isServer())
        {
            this.writeMac = new TlsSuiteHMac(cryptoParams, serverMac);
            this.readMac = new TlsSuiteHMac(cryptoParams, clientMac);
        }
        else
        {
            this.writeMac = new TlsSuiteHMac(cryptoParams, clientMac);
            this.readMac = new TlsSuiteHMac(cryptoParams, serverMac);
        }
    }

    public int getCiphertextLimit(int plaintextLimit)
    {
        int blockSize = encryptCipher.getBlockSize();
        int macSize = writeMac.getSize();

        int ciphertextLimit = plaintextLimit;

        // An explicit IV consumes 1 block
        if (useExplicitIV)
        {
            ciphertextLimit += blockSize;
        }

        // Leave room for the MAC, and require block-alignment
        // Minimum 1 byte of padding
        if (encryptThenMAC)
        {
            ciphertextLimit += blockSize - (ciphertextLimit % blockSize);
            ciphertextLimit += macSize;
        }
        else
        {
            ciphertextLimit += macSize;
            ciphertextLimit += blockSize - (ciphertextLimit % blockSize);
        }

        return ciphertextLimit;
    }

    public int getPlaintextLimit(int ciphertextLimit)
    {
        int blockSize = encryptCipher.getBlockSize();
        int macSize = writeMac.getSize();

        int plaintextLimit = ciphertextLimit;

        // An explicit IV consumes 1 block
        if (useExplicitIV)<commit_msg>Account for possible extra padding in getCiphertextLimit<commit_after>package org.bouncycastle.tls.crypto.impl;

import java.io.IOException;
import java.security.SecureRandom;

import org.bouncycastle.tls.AlertDescription;
import org.bouncycastle.tls.TlsFatalAlert;
import org.bouncycastle.tls.crypto.TlsCipher;
import org.bouncycastle.tls.crypto.TlsCrypto;
import org.bouncycastle.tls.crypto.TlsCryptoParameters;
import org.bouncycastle.tls.crypto.TlsHMAC;
import org.bouncycastle.util.Arrays;

/**
 * A generic TLS 1.0-1.2 block cipher. This can be used for AES or 3DES for example.
 */
public class TlsBlockCipher
    implements TlsCipher
{
    protected final TlsCrypto crypto;
    protected final TlsCryptoParameters cryptoParams;
    protected final byte[] randomData;
    protected final boolean encryptThenMAC;
    protected final boolean useExplicitIV;
    protected final boolean useExtraPadding;

    protected final TlsBlockCipherImpl decryptCipher, encryptCipher;
    protected final TlsSuiteMac readMac, writeMac;

    public TlsBlockCipher(TlsCrypto crypto, TlsCryptoParameters cryptoParams, TlsBlockCipherImpl encryptCipher,
        TlsBlockCipherImpl decryptCipher, TlsHMAC clientMac, TlsHMAC serverMac, int cipherKeySize) throws IOException
    {
        this.cryptoParams = cryptoParams;
        this.crypto = crypto;
        this.randomData = cryptoParams.getNonceGenerator().generateNonce(256);

        this.encryptThenMAC = cryptoParams.getSecurityParameters().isEncryptThenMAC();
        this.useExplicitIV = TlsImplUtils.isTLSv11(cryptoParams);

        /*
         * Don't use variable-length padding with truncated MACs.
         * 
         * See "Tag Size Does Matter: Attacks and Proofs for the TLS Record Protocol", Paterson,
         * Ristenpart, Shrimpton.
         *
         * TODO[DTLS] Consider supporting in DTLS (without exceeding send limit though)
         */
        this.useExtraPadding = !cryptoParams.getServerVersion().isDTLS()
            && (encryptThenMAC || !cryptoParams.getSecurityParameters().isTruncatedHMac());

        this.encryptCipher = encryptCipher;
        this.decryptCipher = decryptCipher;

        TlsBlockCipherImpl clientCipher, serverCipher;
        if (cryptoParams.isServer())
        {
            clientCipher = decryptCipher;
            serverCipher = encryptCipher;
        }
        else
        {
            clientCipher = encryptCipher;
            serverCipher = decryptCipher;
        }

        int key_block_size = (2 * cipherKeySize) + clientMac.getMacLength() + serverMac.getMacLength();

        // From TLS 1.1 onwards, block ciphers don't need IVs from the key_block
        if (!useExplicitIV)
        {
            key_block_size += clientCipher.getBlockSize() + serverCipher.getBlockSize();
        }

        byte[] key_block = TlsImplUtils.calculateKeyBlock(cryptoParams, key_block_size);

        int offset = 0;

        clientMac.setKey(key_block, offset, clientMac.getMacLength());
        offset += clientMac.getMacLength();
        serverMac.setKey(key_block, offset, serverMac.getMacLength());
        offset += serverMac.getMacLength();

        clientCipher.setKey(key_block, offset, cipherKeySize);
        offset += cipherKeySize;
        serverCipher.setKey(key_block, offset, cipherKeySize);
        offset += cipherKeySize;

        if (!useExplicitIV)
        {
            clientCipher.init(key_block, offset, clientCipher.getBlockSize());
            offset += clientCipher.getBlockSize();
            serverCipher.init(key_block, offset, serverCipher.getBlockSize());
            offset += serverCipher.getBlockSize();
        }

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

        if (cryptoParams.isServer())
        {
            this.writeMac = new TlsSuiteHMac(cryptoParams, serverMac);
            this.readMac = new TlsSuiteHMac(cryptoParams, clientMac);
        }
        else
        {
            this.writeMac = new TlsSuiteHMac(cryptoParams, clientMac);
            this.readMac = new TlsSuiteHMac(cryptoParams, serverMac);
        }
    }

    public int getCiphertextLimit(int plaintextLimit)
    {
        int blockSize = encryptCipher.getBlockSize();
        int macSize = writeMac.getSize();

        int ciphertextLimit = plaintextLimit;

        // An explicit IV consumes 1 block
        if (useExplicitIV)
        {
            ciphertextLimit += blockSize;
        }

        int maxPadding = useExtraPadding ? 255 : blockSize;

        // Leave room for the MAC and (block-aligning) padding
        if (encryptThenMAC)
        {
            ciphertextLimit += maxPadding;
            ciphertextLimit -= (ciphertextLimit % blockSize);
            ciphertextLimit += macSize;
        }
        else
        {
            ciphertextLimit += macSize;
            ciphertextLimit += maxPadding;
            ciphertextLimit -= (ciphertextLimit % blockSize);
        }

        return ciphertextLimit;
    }

    public int getPlaintextLimit(int ciphertextLimit)
    {
        int blockSize = encryptCipher.getBlockSize();
        int macSize = writeMac.getSize();

        int plaintextLimit = ciphertextLimit;

        // An explicit IV consumes 1 block
        if (useExplicitIV)
{'fraction_non_alphanumeric': 0.08248112396062315, 'fraction_numerical': 0.003440695785147663, 'mean_word_length': 2.6082758620689654, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5013523', 'n_tokens_mistral': 3049, 'n_tokens_neox': 2898, 'n_words': 643}