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

org.bouncycastle.crypto.fips.FipsTripleDES Maven / Gradle / Ivy

Go to download

The FIPS 140-2 Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms certified to FIPS 140-2 level 1. This jar contains the debug version JCE provider and low-level API for the BC-FJA version 1.0.2.3, FIPS Certificate #3514. Please note the debug jar is not certified.

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

import java.io.InputStream;
import java.io.OutputStream;
import java.security.SecureRandom;
import java.util.logging.Logger;

import org.bouncycastle.crypto.Algorithm;
import org.bouncycastle.crypto.AuthenticationParametersWithIV;
import org.bouncycastle.crypto.CipherOutputStream;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.IllegalKeyException;
import org.bouncycastle.crypto.InvalidWrappingException;
import org.bouncycastle.crypto.OperatorUsingSecureRandom;
import org.bouncycastle.crypto.OutputEncryptor;
import org.bouncycastle.crypto.PlainInputProcessingException;
import org.bouncycastle.crypto.SymmetricKey;
import org.bouncycastle.crypto.SymmetricSecretKey;
import org.bouncycastle.crypto.general.FipsRegister;
import org.bouncycastle.crypto.internal.BufferedBlockCipher;
import org.bouncycastle.crypto.internal.InvalidCipherTextException;
import org.bouncycastle.crypto.internal.KeyGenerationParameters;
import org.bouncycastle.crypto.internal.Mac;
import org.bouncycastle.crypto.internal.MultiBlockCipher;
import org.bouncycastle.crypto.internal.StreamCipher;
import org.bouncycastle.crypto.internal.ValidatedSymmetricKey;
import org.bouncycastle.crypto.internal.Wrapper;
import org.bouncycastle.crypto.internal.io.CipherInputStream;
import org.bouncycastle.crypto.internal.io.CipherOutputStreamImpl;
import org.bouncycastle.crypto.internal.macs.CMac;
import org.bouncycastle.crypto.internal.params.DesEdeParameters;
import org.bouncycastle.crypto.internal.params.KeyParameter;
import org.bouncycastle.crypto.internal.params.KeyParameterImpl;
import org.bouncycastle.crypto.internal.test.BasicKatTest;
import org.bouncycastle.crypto.internal.wrappers.SP80038FWrapEngine;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Properties;
import org.bouncycastle.util.encoders.Hex;

/**
 * Source class for approved implementations of AES based algorithms
 */
public final class FipsTripleDES
{
    private static final Logger LOG = Logger.getLogger(FipsTripleDES.class.getName());

    private FipsTripleDES()
    {

    }

    /**
     * Raw TripleDES algorithm, can be used for creating general purpose TripleDES keys.
     */
    public static final FipsAlgorithm ALGORITHM = new FipsAlgorithm("TripleDES");

    static final FipsEngineProvider ENGINE_PROVIDER;

    /**
     * TripleDES in electronic code book(ECB) mode.
     */
    public static final Parameters ECB = new Parameters(new FipsAlgorithm(ALGORITHM, Mode.ECB));

    /**
     * TripleDES in electronic code book mode with PKCS#7/PKCS#5 padding.
     */
    public static final Parameters ECBwithPKCS7 = new Parameters(new FipsAlgorithm(ALGORITHM, Mode.ECB, Padding.PKCS7));

    /**
     * TripleDES in electronic code book mode with ISO10126-2 padding.
     */
    public static final Parameters ECBwithISO10126_2 = new Parameters(new FipsAlgorithm(ALGORITHM, Mode.ECB, Padding.ISO10126_2));

    /**
     * TripleDES in electronic code book mode with X9.23 padding.
     */
    public static final Parameters ECBwithX923 = new Parameters(new FipsAlgorithm(ALGORITHM, Mode.ECB, Padding.X923));

    /**
     * TripleDES in electronic code book mode with ISO7816-4 padding.
     */
    public static final Parameters ECBwithISO7816_4 = new Parameters(new FipsAlgorithm(ALGORITHM, Mode.ECB, Padding.ISO7816_4));

    /**
     * TripleDES in electronic code book mode with trailing bit complement(TBC) padding.
     */
    public static final Parameters ECBwithTBC = new Parameters(new FipsAlgorithm(ALGORITHM, Mode.ECB, Padding.TBC));

    /**
     * TripleDES in cipher block chaining(CBC) mode.
     */
    public static final ParametersWithIV CBC = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CBC));

    /**
     * TripleDES in cipher block chaining mode with PKCS#7/PKCS#5 padding.
     */
    public static final ParametersWithIV CBCwithPKCS7 = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CBC, Padding.PKCS7));

    /**
     * TripleDES in cipher block chaining mode with ISO10126-2 padding.
     */
    public static final ParametersWithIV CBCwithISO10126_2 = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CBC, Padding.ISO10126_2));

    /**
     * TripleDES in cipher block chaining mode with X9.23 padding.
     */
    public static final ParametersWithIV CBCwithX923 = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CBC, Padding.X923));

    /**
     * TripleDES in cipher block chaining mode with ISO7816-4 padding.
     */
    public static final ParametersWithIV CBCwithISO7816_4 = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CBC, Padding.ISO7816_4));

    /**
     * TripleDES in cipher block chaining mode with trailing bit complement(TBC) padding.
     */
    public static final ParametersWithIV CBCwithTBC = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CBC, Padding.TBC));

    /**
     * TripleDES in cipher block chaining mode cipher text stealing type 1.
     */
    public static final ParametersWithIV CBCwithCS1 = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CBC, Padding.CS1));

    /**
     * TripleDES in cipher block chaining mode cipher text stealing type 2.
     */
    public static final ParametersWithIV CBCwithCS2 = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CBC, Padding.CS2));

    /**
     * TripleDES in cipher block chaining mode cipher text stealing type 3.
     */
    public static final ParametersWithIV CBCwithCS3 = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CBC, Padding.CS3));

    /**
     * TripleDES in cipher feedback(CFB) mode, 8 bit block size.
     */
    public static final ParametersWithIV CFB8 = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CFB8));

    /**
     * TripleDES in output feedback(CFB) mode, 64 bit block size.
     */
    public static final ParametersWithIV CFB64 = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CFB64));

    /**
     * TripleDES in output feedback(OFB) mode, 64 bit blocksize.
     */
    public static final ParametersWithIV OFB = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.OFB64));

    /**
     * TripleDES in counter(CTR) mode.
     */
    public static final ParametersWithIV CTR = new ParametersWithIV(new FipsAlgorithm(ALGORITHM, Mode.CTR));

    /**
     * TripleDES as a FIPS SP800-38F/RFC 3394 key wrapper.
     */
    public static final WrapParameters TKW = new WrapParameters(new FipsAlgorithm(ALGORITHM, Mode.WRAP));

    /**
     * TripleDES CMAC.
     */
    public static final AuthParameters CMAC = new AuthParameters(new FipsAlgorithm(ALGORITHM, Mode.CMAC));

    static
    {
        EngineProvider provider = new EngineProvider();

        // FSM_STATE:5.TDES.0,"TDES ENCRYPT DECRYPT KAT", "The module is performing TDES encrypt and decrypt KAT self-test"
        // FSM_TRANS:5.TDES.0.0,"CONDITIONAL TEST","TDES ENCRYPT DECRYPT KAT", "Invoke TDES Encrypt/Decrypt KAT self-test"
        provider.createEngine();
        // FSM_TRANS:5.TDES.0.1,"TDES ENCRYPT DECRYPT KAT", "CONDITIONAL TEST", "TDES Encrypt/Decrypt KAT self-test successful completion"
        // FSM_TRANS:5.TDES.0.2,"TDES ENCRYPT DECRYPT KAT", "SOFT ERROR", "TDES Encrypt/Decrypt KAT self-test failed"

        // FSM_STATE:5.TDES.1,"TDES-CMAC GENERATE VERIFY KAT", "The module is performing TDES-CMAC generate and verify KAT self-test"
        // FSM_TRANS:5.TDES.1.0, "CONDITIONAL TEST", "TDES-CMAC GENERATE VERIFY KAT", "Invoke TDES CMAC Generate/Verify KAT self-test"
        cmacStartUpTest(provider);
        // FSM_TRANS:5.TDES.1.1, "TDES-CMAC GENERATE VERIFY KAT", "POWER ON SELF-TEST", "TDES CMAC Generate/Verify KAT self-test successful completion"
        // FSM_TRANS:5.TDES.1.2, "TDES-CMAC GENERATE VERIFY KAT", "SOFT ERROR", "TDES CMAC Generate/Verify KAT self-test failed"

        ENGINE_PROVIDER = provider;

        FipsRegister.registerEngineProvider(ALGORITHM, provider);
    }

    /**
     * General Triple-DES operator parameters.
     */
    public static class Parameters
        extends FipsParameters
    {
        Parameters(FipsAlgorithm algorithm)
        {
            super(algorithm);
        }
    }

    /**
     * General Triple-DES operator parameters. with IV
     */
    public static final class ParametersWithIV
        extends Parameters
        implements org.bouncycastle.crypto.ParametersWithIV
    {
        private final byte[] iv;

        ParametersWithIV(FipsAlgorithm algorithm)
        {
            this(algorithm, null);
        }

        private ParametersWithIV(FipsAlgorithm algorithm, byte[] iv)
        {
            super(algorithm);

            ((Mode)algorithm.basicVariation()).checkIv(iv, 8);

            this.iv = iv;
        }

        public ParametersWithIV withIV(byte[] iv)
        {
            return new ParametersWithIV(this.getAlgorithm(), Arrays.clone(iv));
        }

        public ParametersWithIV withIV(SecureRandom random)
        {
            return new ParametersWithIV(this.getAlgorithm(), ((Mode)this.getAlgorithm().basicVariation()).createDefaultIvIfNecessary(8, random));
        }

        public byte[] getIV()
        {
            return Arrays.clone(iv);
        }
    }

    /**
     * Parameters for Triple-DES AEAD and MAC modes..
     */
    public static final class AuthParameters
        extends FipsParameters
        implements AuthenticationParametersWithIV
    {
        private final byte[] iv;
        private final int macLenInBits;

        /**
         * Base constructor - the algorithm. In this case the tag length defaults to the 128 bits.
         *
         * @param algorithm algorithm mode.
         */
        AuthParameters(FipsAlgorithm algorithm)
        {
            this(algorithm, null, Utils.getDefaultMacSize(algorithm, 64));  // tag full blocksize or half
        }

        /**
         * Base Constructor that takes an iv (nonce) and a tag length.
         *
         * @param algorithm    algorithm mode.
         * @param iv           iv, or nonce, to be used with this algorithm.
         * @param macLenInBits length of the checksum tag in bits.
         */
        private AuthParameters(FipsAlgorithm algorithm, byte[] iv, int macLenInBits)
        {
            super(algorithm);

            this.iv = iv;
            this.macLenInBits = macLenInBits;
        }

        public int getMACSizeInBits()
        {
            return macLenInBits;
        }

        public byte[] getIV()
        {
            return Arrays.clone(iv);
        }

        public AuthParameters withIV(byte[] iv)
        {
            return new AuthParameters(this.getAlgorithm(), Arrays.clone(iv), this.macLenInBits);
        }

        public AuthParameters withIV(SecureRandom random)
        {
            return new AuthParameters(this.getAlgorithm(), this.getAlgorithm().createDefaultIvIfNecessary(8, random), this.macLenInBits);
        }

        /**
         * @param random source of randomness for iv (nonce)
         * @param ivLen  length of the iv (nonce) in bytes to use with the algorithm.
         */
        public AuthParameters withIV(SecureRandom random, int ivLen)
        {
            return new AuthParameters(this.getAlgorithm(), this.getAlgorithm().createIvIfNecessary(ivLen, random), this.macLenInBits);
        }

        public AuthParameters withMACSize(int macSizeInBits)
        {
            return new AuthParameters(this.getAlgorithm(), org.bouncycastle.util.Arrays.clone(iv), macSizeInBits);
        }
    }

    /**
     * Parameters for Triple-DES key wrap operators.
     */
    public static final class WrapParameters
        extends FipsParameters
    {
        private final boolean useInverse;

        WrapParameters(FipsAlgorithm algorithm)
        {
            this(algorithm, false);
        }

        private WrapParameters(FipsAlgorithm algorithm, boolean useInverse)
        {
            super(algorithm);

            this.useInverse = useInverse;
        }

        public boolean isUsingInverseFunction()
        {
            return useInverse;
        }

        public WrapParameters withUsingInverseFunction(boolean useInverse)
        {
            return new WrapParameters(getAlgorithm(), useInverse);
        }
    }

    /**
     * Triple-DES key generator.
     */
    public static final class KeyGenerator
        extends FipsSymmetricKeyGenerator
    {
        private final FipsAlgorithm algorithm;
        private final int keySizeInBits;
        private final SecureRandom random;

        /**
         * Constructor to generate a general purpose Triple-DES key.
         *
         * @param keySizeInBits size of the key in bits.
         * @param random        secure random to use in key construction.
         */
        public KeyGenerator(int keySizeInBits, SecureRandom random)
        {
            this(ALGORITHM, keySizeInBits, random);
        }

        /**
         * Constructor to generate a specific purpose Triple-DES key for an algorithm in a particular parameter set.
         *
         * @param parameterSet  FIPS algorithm key is for,
         * @param keySizeInBits size of the key in bits.
         * @param random        secure random to use in key construction.
         */
        public KeyGenerator(FipsParameters parameterSet, int keySizeInBits, SecureRandom random)
        {
            this(parameterSet.getAlgorithm(), keySizeInBits, random);
        }

        private KeyGenerator(FipsAlgorithm algorithm, int keySizeInBits, SecureRandom random)
        {
            if (CryptoServicesRegistrar.isInApprovedOnlyMode())
            {
                Utils.validateKeyGenRandom(random, 112, algorithm);

                if (keySizeInBits != 168 && keySizeInBits != 192)
                {
                    throw new IllegalArgumentException("Attempt to create key with unapproved key size [" + keySizeInBits + "]: " + algorithm.getName());
                }
            }
            else
            {
                if (keySizeInBits != 112 && keySizeInBits != 168 && keySizeInBits != 128 && keySizeInBits != 192)
                {
                    throw new IllegalArgumentException("Attempt to create key with invalid key size [" + keySizeInBits + "]: " + algorithm.getName());
                }
            }

            this.algorithm = algorithm;
            this.keySizeInBits = keySizeInBits;
            this.random = random;
        }

        public SymmetricKey generateKey()
        {
            CipherKeyGenerator cipherKeyGenerator = new DesEdeKeyGenerator(algorithm);

            cipherKeyGenerator.init(new KeyGenerationParameters(random, keySizeInBits));

            return new SymmetricSecretKey(algorithm, cipherKeyGenerator.generateKey());
        }
    }

    /**
     * Factory for basic Triple-DES encryption/decryption operators.
     */
    public static final class OperatorFactory
        extends FipsSymmetricOperatorFactory
    {
        @Override
        public FipsOutputEncryptor createOutputEncryptor(final SymmetricKey key, final Parameters parameters)
        {
            final ValidatedSymmetricKey sKey = validateKey(key, parameters, false);

            return new OutEncryptor(sKey, parameters, null);
        }

        @Override
        public FipsOutputDecryptor createOutputDecryptor(final SymmetricKey key, final Parameters parameters)
        {
            ValidatedSymmetricKey sKey = validateKey(key, parameters, true);

            final BufferedBlockCipher cipher = BlockCipherUtils.createStandardCipher(false, sKey, ENGINE_PROVIDER, parameters, null);

            return new FipsOutputDecryptor()
            {
                @Override
                public Parameters getParameters()
                {
                    return parameters;
                }

                public int getMaxOutputSize(int inputLen)
                {
                    return cipher.getOutputSize(inputLen);
                }

                public int getUpdateOutputSize(int inputLen)
                {
                    return cipher.getUpdateOutputSize(inputLen);
                }

                @Override
                public CipherOutputStream getDecryptingStream(OutputStream out)
                {
                    if (cipher.getUnderlyingCipher() instanceof StreamCipher)
                    {
                        return CipherOutputStreamImpl.getInstance(out, (StreamCipher)cipher.getUnderlyingCipher());
                    }

                    return CipherOutputStreamImpl.getInstance(out, cipher);
                }
            };
        }

        @Override
        public FipsInputDecryptor createInputDecryptor(final SymmetricKey key, final Parameters parameters)
        {
            final ValidatedSymmetricKey sKey = validateKey(key, parameters, true);
            final BufferedBlockCipher cipher = BlockCipherUtils.createStandardCipher(false, sKey, ENGINE_PROVIDER, parameters, null);

            return new FipsInputDecryptor()
            {
                @Override
                public Parameters getParameters()
                {
                    return parameters;
                }

                @Override
                public InputStream getDecryptingStream(InputStream in)
                {
                    if (cipher.getUnderlyingCipher() instanceof StreamCipher)
                    {
                        return new CipherInputStream(in, (StreamCipher)cipher.getUnderlyingCipher());
                    }

                    return new CipherInputStream(in, cipher);
                }
            };
        }

        private class OutEncryptor
            extends FipsOutputEncryptor
            implements OperatorUsingSecureRandom>
        {
            private final Parameters parameters;
            private final ValidatedSymmetricKey key;
            private final BufferedBlockCipher cipher;

            public OutEncryptor(ValidatedSymmetricKey key, Parameters parameters, SecureRandom random)
            {
                if (CryptoServicesRegistrar.isInApprovedOnlyMode())
                {
                    if (!Properties.isOverrideSet("org.bouncycastle.tripledes.allow_enc"))
                    {
                        throw new FipsUnapprovedOperationError("Triple-DES encryption disallowed");
                    }

                    LOG.warning("Triple-DES encryption detected: no longer an approved operation but override set");
                }

                this.key = key;
                this.parameters = parameters;

                cipher = BlockCipherUtils.createStandardCipher(true, key, ENGINE_PROVIDER, parameters, random);
            }

            public CipherOutputStream getEncryptingStream(OutputStream out)
            {
                if (cipher.getUnderlyingCipher() instanceof StreamCipher)
                {
                    return CipherOutputStreamImpl.getInstance(out, (StreamCipher)cipher.getUnderlyingCipher());
                }

                return CipherOutputStreamImpl.getInstance(out, cipher);
            }

            public OutputEncryptor withSecureRandom(SecureRandom random)
            {
                return new OutEncryptor(key, parameters, random);
            }

            public Parameters getParameters()
            {
                return parameters;
            }

            public int getMaxOutputSize(int inputLen)
            {
                return cipher.getOutputSize(inputLen);
            }

            public int getUpdateOutputSize(int inputLen)
            {
                return cipher.getUpdateOutputSize(inputLen);
            }
        }
    }

    /**
     * Factory for producing FIPS Triple-DES MAC calculators.
     */
    public static final class MACOperatorFactory
        extends FipsMACOperatorFactory
    {
        @Override
        protected int calculateMACSize(AuthParameters parameters)
        {
            return makeMAC(parameters).getMacSize();
        }

        @Override
        protected Mac createMAC(SymmetricKey key, final AuthParameters parameters)
        {
            final Mac mac = makeMAC(parameters);
            ValidatedSymmetricKey sKey = validateKey(key, parameters, false);

            if (parameters.getIV() != null)
            {
                mac.init(Utils.getParametersWithIV(sKey, parameters.getIV()));
            }
            else
            {
                mac.init(Utils.getKeyParameter(sKey));
            }

            return mac;
        }
    }

    static FipsEngineProvider getMacProvider(final FipsAlgorithm algorithm)
    {
        final FipsEngineProvider macProvider;

        switch (((Mode)algorithm.basicVariation()))
        {
        case CMAC:
            macProvider = new FipsEngineProvider()
            {
                public Mac createEngine()
                {
                    return new CMac(ENGINE_PROVIDER.createEngine());
                }
            };
            break;
        default:
            throw new IllegalArgumentException("Unknown algorithm passed to FipsTripleDES MAC Provider: " + algorithm);
        }

        return macProvider;
    }

    static Mac makeMAC(final AuthParameters authParameters)
    {
        final Mac mac;

        switch (((Mode)authParameters.getAlgorithm().basicVariation()))
        {
        case CMAC:
            mac = new CMac(ENGINE_PROVIDER.createEngine(), authParameters.macLenInBits);
            break;
        default:
            throw new IllegalArgumentException("Unknown algorithm passed to FipsTripleDES.OperatorFactory.createMACCalculator: " + authParameters.getAlgorithm());
        }

        return mac;
    }

    /**
     * Factory for producing FIPS Triple-DES key wrap/unwrap operators.
     */
    public static final class KeyWrapOperatorFactory
        extends FipsKeyWrapOperatorFactory
    {
        private Wrapper createWrapper(FipsAlgorithm algorithm, boolean useInverse)
        {
            Wrapper cipher;

            switch (((Mode)algorithm.basicVariation()))
            {
            case WRAP:
                cipher = new SP80038FWrapEngine(ENGINE_PROVIDER.createEngine(), useInverse);
                break;
            default:
                throw new IllegalArgumentException("Unknown algorithm passed to FipsDESEDE.KeyWrapOperatorFactory: " + algorithm.getName());
            }

            return cipher;
        }

        @Override
        public FipsKeyWrapper createKeyWrapper(SymmetricKey key, final WrapParameters parameters)
        {
            ValidatedSymmetricKey sKey = validateKey(key, parameters, false);
            final Wrapper wrapper = createWrapper(parameters.getAlgorithm(), parameters.useInverse);

            wrapper.init(true, new KeyParameterImpl(sKey.getKeyBytes()));

            return new FipsKeyWrapper()
            {
                public WrapParameters getParameters()
                {
                    return parameters;
                }

                public byte[] wrap(byte[] in, int inOff, int inLen)
                    throws PlainInputProcessingException
                {
                    if (CryptoServicesRegistrar.isInApprovedOnlyMode())
                    {
                        if (!Properties.isOverrideSet("org.bouncycastle.tripledes.allow_wrap"))
                        {
                            throw new FipsUnapprovedOperationError("Triple-DES encryption key-wrapping disallowed");
                        }

                        LOG.warning("Triple-DES encryption key-wrapping detected: no longer an approved operation but override set");
                    }

                    try
                    {
                        return wrapper.wrap(in, inOff, inLen);
                    }
                    catch (Exception e)
                    {
                        throw new PlainInputProcessingException("Unable to wrap key: " + e.getMessage(), e);
                    }
                }
            };
        }

        @Override
        public FipsKeyUnwrapper createKeyUnwrapper(SymmetricKey key, final WrapParameters parameters)
        {
            ValidatedSymmetricKey sKey = validateKey(key, parameters, true);

            final Wrapper wrapper = createWrapper(parameters.getAlgorithm(), parameters.useInverse);

            wrapper.init(false, new KeyParameterImpl(sKey.getKeyBytes()));

            return new FipsKeyUnwrapper()
            {
                public WrapParameters getParameters()
                {
                    return parameters;
                }

                @Override
                public byte[] unwrap(byte[] in, int inOff, int inLen)
                    throws InvalidWrappingException
                {
                    try
                    {
                        return wrapper.unwrap(in, inOff, inLen);
                    }
                    catch (InvalidCipherTextException e)
                    {
                        throw new InvalidWrappingException("Unable to unwrap key: " + e.getMessage(), e);
                    }
                }
            };
        }
    }

    private static void validateKeySize(Algorithm algorithm, int keySize)
    {
        if (CryptoServicesRegistrar.isInApprovedOnlyMode())
        {
            if (keySize != 168 && keySize != 192)
            {
                // FSM_TRANS:5.TDES.2.2,"TDES KEY VALIDITY TEST", "USER COMMAND REJECTED", "Validity test on TDES key failed"
                throw new IllegalKeyException("Key must be of length 192 bits: " + algorithm.getName());
            }
        }
        else
        {
            if (keySize != 112 && keySize != 168 && keySize != 128 && keySize != 192)
            {
                throw new IllegalKeyException("Key must be of length 128 or 192 bits: " + algorithm.getName());
            }
        }
    }

    private static ValidatedSymmetricKey validateKey(SymmetricKey key, org.bouncycastle.crypto.Parameters parameters, boolean forReading)
    {
        // FSM_STATE:5.TDES.2,"TDES KEY VALIDITY TEST", "The module is validating the size and purpose of an TDES key"
        // FSM_TRANS:5.TDES.2.0,"CONDITIONAL TEST", "TDES KEY VALIDITY TEST", "Invoke Validity test on TDES key"
        ValidatedSymmetricKey vKey = PrivilegedUtils.getValidatedKey(key);

        int keyLength = vKey.getKeySizeInBits();
        if (!(forReading && keyLength == 128))      // decryption using 2 key TDES okay,
        {
            validateKeySize(key.getAlgorithm(), keyLength);

            if (CryptoServicesRegistrar.isInApprovedOnlyMode())
            {
                if (!forReading && !DesEdeParameters.isReal3Key(vKey.getKeyBytes()))
                {
                    // FSM_TRANS:5.TDES.2.2,"TDES KEY VALIDITY TEST", "USER COMMAND REJECTED", "Validity test on TDES key failed"
                    throw new IllegalKeyException("Key not real 3-Key DESEDE key");
                }
            }
        }

        if (!Properties.isOverrideSet("org.bouncycastle.tripledes.allow_weak"))
        {
            if (!forReading)
            {
                if (DesEdeParameters.isActuallyDesKey(vKey.getKeyBytes()))
                {
                    // FSM_TRANS:5.TDES.2.2,"TDES KEY VALIDITY TEST", "USER COMMAND REJECTED", "Validity test on TDES key failed"
                    throw new IllegalKeyException("Attempt to use repeated DES key: " + key.getAlgorithm().getName());
                }
                if (DesEdeParameters.isWeakKey(vKey.getKeyBytes(), 0, vKey.getKeyBytes().length))
                {
                    // FSM_TRANS:5.TDES.2.2,"TDES KEY VALIDITY TEST", "USER COMMAND REJECTED", "Validity test on TDES key failed"
                    throw new IllegalKeyException("Attempt to use weak key: " + key.getAlgorithm().getName());
                }
            }
        }

        Algorithm algorithm = key.getAlgorithm();

        if (!algorithm.equals(ALGORITHM))
        {
            if (!algorithm.equals(parameters.getAlgorithm()))
            {
                // FSM_TRANS:5.TDES.2.2,"TDES KEY VALIDITY TEST", "USER COMMAND REJECTED", "Validity test on TDES key failed"
                throw new IllegalKeyException("FIPS Key not for specified algorithm");
            }
        }

        // FSM_TRANS:5.TDES.2.1,"TDES KEY VALIDITY TEST", "CONDITIONAL TEST", "Validity test on TDES key successful"
        return vKey;
    }

    private static final class EngineProvider
        extends FipsEngineProvider
    {
        private static byte[] input = Hex.decode("4e6f772069732074");
        private static byte[] output = Hex.decode("f7cfbe5e6c38b35a");

        private static final byte[] keyBytes = Hex.decode("0102020404070708080b0b0d0d0e0e101013131515161619");

        public MultiBlockCipher createEngine()
        {
            return SelfTestExecutor.validate(ALGORITHM, new DesEdeEngine(), new VariantKatTest()
            {
                public void evaluate(DesEdeEngine tripleDesEngine)
                {

                    byte[] tmp = new byte[input.length];

                    KeyParameter key = new KeyParameterImpl(keyBytes);

                    tripleDesEngine.init(true, key);

                    tripleDesEngine.processBlock(input, 0, tmp, 0);

                    if (!Arrays.areEqual(output, tmp))
                    {
                        fail("Failed self test on encryption");
                    }

                    tripleDesEngine.init(false, key);

                    tripleDesEngine.processBlock(tmp, 0, tmp, 0);

                    if (!Arrays.areEqual(input, tmp))
                    {
                        fail("Failed self test on decryption");
                    }
                }
            });
        }
    }

    private static void cmacStartUpTest(EngineProvider provider)
    {
        SelfTestExecutor.validate(ALGORITHM, provider, new BasicKatTest()
        {
            public boolean hasTestPassed(EngineProvider provider)
                throws Exception
            {
                byte[] input16 = Hex.decode("6bc1bee22e409f96e93d7e117393172a");
                byte[] output_k128_m16 = Hex.decode("c0b9bbee139722ab");

                Mac mac = new CMac(provider.createEngine(), 64);

                //128 bytes key

                KeyParameter key = new KeyParameterImpl(Hex.decode("0102020404070708080b0b0d0d0e0e101013131515161619"));

                // 0 bytes message - 128 bytes key
                mac.init(key);

                mac.update(input16, 0, input16.length);

                byte[] out = new byte[8];

                mac.doFinal(out, 0);

                return Arrays.areEqual(out, output_k128_m16);
            }
        });
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy