All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.crypto.general.CipherUtils Maven / Gradle / Ivy

Go to download

The FIPS 140-3 Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms certified to FIPS 140-3 level 1. This jar contains JCE provider and low-level API for the BC-FJA version 2.0.0, FIPS Certificate #4743. Please see certificate for certified platform details.

There is a newer version: 2.0.0
Show newest version
package org.bouncycastle.crypto.general;

import java.security.SecureRandom;

import org.bouncycastle.crypto.AuthenticationParameters;
import org.bouncycastle.crypto.AuthenticationParametersWithIV;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.Parameters;
import org.bouncycastle.crypto.ParametersWithIV;
import org.bouncycastle.crypto.fips.FipsDRBG;
import org.bouncycastle.crypto.internal.BlockCipher;
import org.bouncycastle.crypto.internal.BufferedBlockCipher;
import org.bouncycastle.crypto.internal.CipherParameters;
import org.bouncycastle.crypto.internal.EngineProvider;
import org.bouncycastle.crypto.internal.Mac;
import org.bouncycastle.crypto.internal.ValidatedSymmetricKey;
import org.bouncycastle.crypto.internal.Wrapper;
import org.bouncycastle.crypto.internal.macs.AEADCipherMac;
import org.bouncycastle.crypto.internal.macs.CBCBlockCipherMac;
import org.bouncycastle.crypto.internal.macs.CFBBlockCipherMac;
import org.bouncycastle.crypto.internal.macs.CMac;
import org.bouncycastle.crypto.internal.macs.GMac;
import org.bouncycastle.crypto.internal.modes.AEADBlockCipher;
import org.bouncycastle.crypto.internal.modes.CBCBlockCipher;
import org.bouncycastle.crypto.internal.modes.CCMBlockCipher;
import org.bouncycastle.crypto.internal.modes.CFBBlockCipher;
import org.bouncycastle.crypto.internal.modes.EAXBlockCipher;
import org.bouncycastle.crypto.internal.modes.GCFBBlockCipher;
import org.bouncycastle.crypto.internal.modes.GCMBlockCipher;
import org.bouncycastle.crypto.internal.modes.GOFBBlockCipher;
import org.bouncycastle.crypto.internal.modes.NISTCTSBlockCipher;
import org.bouncycastle.crypto.internal.modes.OCBBlockCipher;
import org.bouncycastle.crypto.internal.modes.OFBBlockCipher;
import org.bouncycastle.crypto.internal.modes.OpenPGPCFBBlockCipher;
import org.bouncycastle.crypto.internal.modes.SICBlockCipher;
import org.bouncycastle.crypto.internal.paddings.ISO10126d2Padding;
import org.bouncycastle.crypto.internal.paddings.ISO7816d4Padding;
import org.bouncycastle.crypto.internal.paddings.PKCS7Padding;
import org.bouncycastle.crypto.internal.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.internal.paddings.TBCPadding;
import org.bouncycastle.crypto.internal.paddings.X923Padding;
import org.bouncycastle.crypto.internal.params.KeyParameter;
import org.bouncycastle.crypto.internal.params.KeyParameterImpl;
import org.bouncycastle.crypto.internal.params.ParametersWithRandom;
import org.bouncycastle.crypto.internal.wrappers.SP80038FWrapEngine;
import org.bouncycastle.crypto.internal.wrappers.SP80038FWrapWithPaddingEngine;
import org.bouncycastle.util.Pack;
import org.bouncycastle.util.Strings;

class CipherUtils
{
    private static SecureRandom defaultRandomPadder;

    static BufferedBlockCipher createBlockCipher(EngineProvider provider, Parameters parameter)
    {
        GeneralAlgorithm algorithm = (GeneralAlgorithm)parameter.getAlgorithm();
        BlockCipher cipher = provider.createEngine();
        Padding padding = (Padding)algorithm.additionalVariation();

        switch (((Mode)algorithm.basicVariation()))
        {
        case ECB:
            break;
        case CBC:
            if (padding != Padding.CS1 && padding != Padding.CS2 && padding != Padding.CS3)
            {
                cipher = new CBCBlockCipher(cipher);
            }
            break;
        case CFB8:
            cipher = new CFBBlockCipher(cipher, 8);
            break;
        case CFB64:
            cipher = new CFBBlockCipher(cipher, 64);
            break;
        case CFB128:
            cipher = new CFBBlockCipher(cipher, 128);
            break;
        case CFB256:
            cipher = new CFBBlockCipher(cipher, 256);
            break;
        case OFB64:
            cipher = new OFBBlockCipher(cipher, 64);
            break;
        case OFB128:
            cipher = new OFBBlockCipher(cipher, 128);
            break;
        case OFB256:
            cipher = new OFBBlockCipher(cipher, 256);
            break;
        case CTR:
            cipher = new SICBlockCipher(cipher);
            break;
        case OpenPGPCFB:
            cipher = new OpenPGPCFBBlockCipher(cipher);
            break;
        case GCFB:
            cipher = new GCFBBlockCipher(cipher);
            break;
        case GOFB:
            cipher = new GOFBBlockCipher(cipher);
            break;
        default:
            throw new IllegalArgumentException("Unknown algorithm passed to createBlockCipher: " + algorithm.getName());
        }

        if (padding != null)
        {
            switch (padding)
            {
            case PKCS7:
                return new PaddedBufferedBlockCipher(cipher, new PKCS7Padding());
            case ISO7816_4:
                return new PaddedBufferedBlockCipher(cipher, new ISO7816d4Padding());
            case ISO10126_2:
                return new PaddedBufferedBlockCipher(cipher, new ISO10126d2Padding());
            case TBC:
                return new PaddedBufferedBlockCipher(cipher, new TBCPadding());
            case X923:
                return new PaddedBufferedBlockCipher(cipher, new X923Padding());
            case CS1:
                return new NISTCTSBlockCipher(NISTCTSBlockCipher.CS1, cipher);
            case CS2:
                return new NISTCTSBlockCipher(NISTCTSBlockCipher.CS2, cipher);
            case CS3:
                return new NISTCTSBlockCipher(NISTCTSBlockCipher.CS3, cipher);
            default:
                throw new IllegalArgumentException("Unknown padding passed to createBlockCipher: " + parameter.getAlgorithm());
            }
        }

        return new BufferedBlockCipher(cipher);
    }

    static BufferedBlockCipher createStandardCipher(boolean forEncryption, ValidatedSymmetricKey key, EngineProvider engineProvider, ParametersWithIV parameters, SecureRandom random)
    {
        KeyParameter keyParameter = new KeyParameterImpl(key.getKeyBytes());

        return createStandardCipher(forEncryption, keyParameter, engineProvider, parameters, random);
    }

    static BufferedBlockCipher createStandardCipher(boolean forEncryption, KeyParameter keyParameter, EngineProvider engineProvider, ParametersWithIV parameters, SecureRandom random)
    {
        BufferedBlockCipher cipher = CipherUtils.createBlockCipher(engineProvider, parameters);

        CipherParameters cipherParameters = keyParameter;

        if (parameters.getIV() != null)
        {
            cipherParameters = new org.bouncycastle.crypto.internal.params.ParametersWithIV(cipherParameters, parameters.getIV());
        }

        if (((GeneralAlgorithm)parameters.getAlgorithm()).additionalVariation() instanceof Padding)
        {
            Padding padding = (Padding)((GeneralAlgorithm)parameters.getAlgorithm()).additionalVariation();

            if (padding.getBasePadding().requiresRandom() && forEncryption)
            {
                if (random != null)
                {
                    cipherParameters = new ParametersWithRandom(cipherParameters, random);
                }
                else
                {
                    try
                    {
                        cipherParameters = new ParametersWithRandom(cipherParameters, CryptoServicesRegistrar.getSecureRandom());
                    }
                    catch (IllegalStateException e)
                    {
                        cipherParameters = new ParametersWithRandom(cipherParameters, getDefaultRandomPadder());
                    }
                }
            }
        }

        cipher.init(forEncryption, cipherParameters);

        return cipher;
    }

    static AEADBlockCipher createAEADCipher(GeneralAlgorithm algorithm, EngineProvider provider)
    {
        AEADBlockCipher cipher;

        switch (((Mode)algorithm.basicVariation()))
        {
        case CCM:
            cipher = new CCMBlockCipher(provider.createEngine());
            break;
        case EAX:
            cipher = new EAXBlockCipher(provider.createEngine());
            break;
        case GCM:
            cipher = new GCMBlockCipher(provider.createEngine());
            break;
        case OCB:
            cipher = new OCBBlockCipher(provider.createEngine(), provider.createEngine());
            break;
        default:
            throw new IllegalArgumentException("Unknown algorithm passed to createAEADCipher: " + algorithm.getName());
        }

        return cipher;
    }

    static AEADBlockCipher createStandardAEADCipher(boolean forEncryption, ValidatedSymmetricKey key, EngineProvider engineProvider,
                                                    final AuthenticationParametersWithIV parameters)
    {
        KeyParameter keyParameter = new KeyParameterImpl(key.getKeyBytes());

        return createStandardAEADCipher(forEncryption, keyParameter, engineProvider, parameters);
    }

    static AEADBlockCipher createStandardAEADCipher(boolean forEncryption, KeyParameter keyParameter, EngineProvider engineProvider,
                                                    final AuthenticationParametersWithIV parameters)
    {
        final AEADBlockCipher cipher = CipherUtils.createAEADCipher((GeneralAlgorithm)parameters.getAlgorithm(), engineProvider);

        if (parameters.getIV() != null)
        {
            cipher.init(forEncryption, new org.bouncycastle.crypto.internal.params.AEADParameters(keyParameter, parameters.getMACSizeInBits(), parameters.getIV()));
        }
        else
        {
            cipher.init(forEncryption, keyParameter);
        }

        return cipher;
    }

    static Mac createStandardMac(ValidatedSymmetricKey key, EngineProvider provider, GeneralAuthParameters parameters)
    {
        KeyParameter keyParameter = new KeyParameterImpl(key.getKeyBytes());

        return createStandardMac(keyParameter, provider, parameters);
    }

    static Mac createStandardMac(KeyParameter keyParameter, EngineProvider provider, GeneralAuthParameters parameters)
    {
        final Mac mac = getMac(parameters, provider);

        if (parameters.getIV() != null)
        {
            mac.init(new org.bouncycastle.crypto.internal.params.ParametersWithIV(keyParameter, parameters.getIV()));
        }
        else
        {
            mac.init(keyParameter);
        }

        return mac;
    }

    private static Mac getMac(AuthenticationParameters parameters, EngineProvider provider)
    {
        Mac mac;
        Padding pad = (Padding)((GeneralAlgorithm)parameters.getAlgorithm()).additionalVariation();

        switch (((Mode)((GeneralAlgorithm)parameters.getAlgorithm()).basicVariation()))
        {
        case CBCMAC:
            if (pad != null)
            {
                if (pad == Padding.ISO7816_4)
                {
                    mac = new CBCBlockCipherMac(provider.createEngine(), parameters.getMACSizeInBits(), new ISO7816d4Padding());
                }
                else
                {
                    throw new IllegalArgumentException("Unknown padding passed to MAC operator factory: " + parameters.getAlgorithm().getName());
                }
            }
            else
            {
                mac = new CBCBlockCipherMac(provider.createEngine(), parameters.getMACSizeInBits());
            }
            break;
        case CCM:
            mac = new AEADCipherMac(new CCMBlockCipher(provider.createEngine()), parameters.getMACSizeInBits());
            break;
        case CMAC:
            mac = new CMac(provider.createEngine(), parameters.getMACSizeInBits());
            break;
        case GMAC:
            mac = new GMac(new GCMBlockCipher(provider.createEngine()), parameters.getMACSizeInBits());
            break;
        case CFB8MAC:
            mac = new CFBBlockCipherMac(provider.createEngine());
            break;
        case GOSTMAC:
            mac = new GOST28147Mac();
            break;
        case ISO9797alg3:
            if (pad != null)
            {
                if (pad == Padding.ISO7816_4)
                {
                    mac = new ISO9797Alg3Mac(provider.createEngine(), parameters.getMACSizeInBits(), new ISO7816d4Padding());
                }
                else
                {
                    throw new IllegalArgumentException("Unknown padding passed to MAC operator factory: " + parameters.getAlgorithm().getName());
                }
            }
            else
            {
                mac = new ISO9797Alg3Mac(provider.createEngine());
            }
            break;
        default:
            throw new IllegalArgumentException("Unknown algorithm passed to MAC operator factory: " + parameters.getAlgorithm().getName());
        }
        return mac;
    }

    static Wrapper createStandardWrapper(boolean forWrapping, ValidatedSymmetricKey key, EngineProvider provider, ParametersWithIV parameters, SecureRandom random)
    {
        return createStandardWrapper(forWrapping, new KeyParameterImpl(key.getKeyBytes()), provider, parameters, false, random);
    }

    static Wrapper createStandardWrapper(boolean forWrapping, ValidatedSymmetricKey key, EngineProvider provider, ParametersWithIV parameters, boolean useInverse, SecureRandom random)
    {
        return createStandardWrapper(forWrapping, new KeyParameterImpl(key.getKeyBytes()), provider, parameters, useInverse, random);
    }

    static Wrapper createStandardWrapper(boolean forWrapping, KeyParameter keyParameter, EngineProvider provider, ParametersWithIV parameters, boolean useInverse, SecureRandom random)
    {
        GeneralAlgorithm algorithm = (GeneralAlgorithm)parameters.getAlgorithm();
        boolean randomRequired = false;
        Wrapper wrapper;

        switch (((Mode)algorithm.basicVariation()))
        {
        case WRAP:
            wrapper = new SP80038FWrapEngine(provider.createEngine(), useInverse);
            break;
        case WRAPPAD:
            wrapper = new SP80038FWrapWithPaddingEngine(provider.createEngine(), useInverse);
            break;
        case RFC3211_WRAP:
            randomRequired = true;
            wrapper = new RFC3211WrapEngine(provider.createEngine());
            break;
        case RFC3217_WRAP:
            randomRequired = true;
            if (algorithm.equals(TripleDES.RFC3217_WRAP.getAlgorithm()))
            {
                wrapper = new DesEdeWrapEngine();
            }
            else if (algorithm.equals(RC2.RFC3217_WRAP.getAlgorithm()))
            {
                wrapper = new RC2WrapEngine();
            }
            else
            {
                throw new IllegalArgumentException("Unknown RFC3217 algorithm passed to Key Wrap operator factory: " + algorithm.getName());
            }
            break;
        default:
            throw new IllegalArgumentException("Unknown algorithm passed to Key Wrap operator factory: " + algorithm.getName());
        }

        CipherParameters params = keyParameter;

        if (parameters.getIV() != null)
        {
            params = new org.bouncycastle.crypto.internal.params.ParametersWithIV(keyParameter, parameters.getIV());
        }

        if (forWrapping && randomRequired)
        {
            if (random != null)
            {
                params = new ParametersWithRandom(params, random);
            }
            else
            {
                throw new IllegalArgumentException("No SecureRandom provided when one required");
            }
        }

        wrapper.init(forWrapping, params);

        return wrapper;
    }


    static synchronized SecureRandom getDefaultRandomPadder()
    {
        if (defaultRandomPadder == null)
        {
            defaultRandomPadder = FipsDRBG.SHA512.fromDefaultEntropy().
                setPersonalizationString(Strings.toByteArray("Bouncy Castle General Default Padder"))
                .build(Pack.longToBigEndian(System.currentTimeMillis()), false);
        }

        return defaultRandomPadder;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy