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

org.bouncycastle.jcajce.provider.ProvLMS 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.jcajce.provider;

import java.io.IOException;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.security.SignatureSpi;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.HashMap;
import java.util.Map;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.crypto.Algorithm;
import org.bouncycastle.crypto.AsymmetricKey;
import org.bouncycastle.crypto.AsymmetricPrivateKey;
import org.bouncycastle.crypto.AsymmetricPublicKey;
import org.bouncycastle.crypto.OutputSigner;
import org.bouncycastle.crypto.OutputVerifier;
import org.bouncycastle.crypto.Parameters;
import org.bouncycastle.crypto.SignatureOperatorFactory;
import org.bouncycastle.crypto.UpdateOutputStream;
import org.bouncycastle.crypto.asymmetric.AsymmetricKeyPair;
import org.bouncycastle.crypto.asymmetric.AsymmetricLMSPrivateKey;
import org.bouncycastle.crypto.asymmetric.AsymmetricLMSPublicKey;
import org.bouncycastle.crypto.fips.FipsLMS;
import org.bouncycastle.jcajce.spec.LMSHSSKeyGenParameterSpec;
import org.bouncycastle.jcajce.spec.LMSKeyGenParameterSpec;

final class ProvLMS
    extends AsymmetricAlgorithmProvider
{
    private static final Map generalAttributes = new HashMap();

    static
    {
        generalAttributes.put("SupportedKeyClasses", "org.bouncycastle.interfaces.LMSKey");
        generalAttributes.put("SupportedKeyFormats", "PKCS#8|X.509");
    }

    private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".lms.";

    private static final PublicKeyConverter lmsPublicKeyConverter = new PublicKeyConverter()
    {
        public AsymmetricLMSPublicKey convertKey(Algorithm algorithm, PublicKey key)
            throws InvalidKeyException
        {
            if (key instanceof ProvLMSPublicKey)
            {
                return ((ProvLMSPublicKey)key).getBaseKey();
            }
            else
            {
                // see if we can build a key from key.getEncoded()
                try
                {
                    return new AsymmetricLMSPublicKey(Utils.getKeyEncoding(key));
                }
                catch (Exception e)
                {
                    throw new InvalidKeyException("Cannot identify LMS public key: " + e.getMessage(), e);
                }
            }
        }
    };

    private static final PrivateKeyConverter lmsPrivateKeyConverter = new PrivateKeyConverter()
    {
        public AsymmetricLMSPrivateKey convertKey(Algorithm algorithm, PrivateKey key)
            throws InvalidKeyException
        {
            if (key instanceof ProvLMSPrivateKey)
            {
                return ((ProvLMSPrivateKey)key).getBaseKey();
            }
            else
            {
                // see if we can build a key from key.getEncoded()
                try
                {
                    return new AsymmetricLMSPrivateKey(PrivateKeyInfo.getInstance(Utils.getKeyEncoding(key)));
                }
                catch (Exception e)
                {
                    throw new InvalidKeyException("Cannot identify LMS private key: " + e.getMessage(), e);
                }
            }
        }
    };

    static class KeyFactorySpi
        extends BaseKeyFactory
    {
        String algorithm;

        public KeyFactorySpi(
            String algorithm)
        {
            this.algorithm = algorithm;
        }

        protected Key engineTranslateKey(
            Key key)
            throws InvalidKeyException
        {
            if (key instanceof PublicKey)
            {
                return new ProvLMSPublicKey(lmsPublicKeyConverter.convertKey(FipsLMS.ALGORITHM, (PublicKey)key));
            }
            else if (key instanceof PrivateKey)
            {
                return new ProvLMSPrivateKey(lmsPrivateKeyConverter.convertKey(FipsLMS.ALGORITHM, (PrivateKey)key));
            }
            else if (key != null)
            {
                throw new InvalidKeyException("Key type unrecognized: " + key.getClass().getName());
            }
            throw new InvalidKeyException("Key is null");
        }

        protected KeySpec engineGetKeySpec(
            Key key,
            Class spec)
            throws InvalidKeySpecException
        {
            if (spec == null)
            {
                throw new InvalidKeySpecException("null spec is invalid");
            }

            return super.engineGetKeySpec(key, spec);
        }

        protected PrivateKey engineGeneratePrivate(
            KeySpec keySpec)
            throws InvalidKeySpecException
        {
            return super.engineGeneratePrivate(keySpec);
        }

        protected PublicKey engineGeneratePublic(
            KeySpec keySpec)
            throws InvalidKeySpecException
        {
            return super.engineGeneratePublic(keySpec);
        }

        public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
            throws IOException
        {
            ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();

            if (algOid.equals(PKCSObjectIdentifiers.id_alg_hss_lms_hashsig))
            {
                return new ProvLMSPrivateKey(keyInfo);
            }

            throw new IOException("algorithm identifier " + algOid + " in key not recognized");
        }

        public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
            throws IOException
        {
            ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();

            if (algOid.equals(PKCSObjectIdentifiers.id_alg_hss_lms_hashsig))
            {
                return new ProvLMSPublicKey(keyInfo);
            }

            throw new IOException("algorithm identifier " + algOid + " in key not recognized");
        }
    }

    static class KeyPairGeneratorSpi
        extends java.security.KeyPairGenerator
    {
        private final BouncyCastleFipsProvider provider;

        FipsLMS.KeyGenParameters param;
        FipsLMS.KeyPairGenerator engine;

        SecureRandom random;
        boolean initialised = false;

        public KeyPairGeneratorSpi(BouncyCastleFipsProvider provider)
        {
            super("LMS");
            this.provider = provider;
        }

        public void initialize(
            int strength)
        {
            initialize(strength, provider.getDefaultSecureRandom());
        }

        public void initialize(
            int strength,
            SecureRandom random)
        {
            throw new UnsupportedOperationException("use AlgorithmParameterSpec");
        }

        public void initialize(
            AlgorithmParameterSpec params)
            throws InvalidAlgorithmParameterException
        {
            initialize(params, provider.getDefaultSecureRandom());
        }

        public void initialize(
            AlgorithmParameterSpec params,
            SecureRandom random)
            throws InvalidAlgorithmParameterException
        {
            if (params instanceof LMSKeyGenParameterSpec)
            {
                LMSKeyGenParameterSpec lmsParams = (LMSKeyGenParameterSpec)params;

                param = new FipsLMS.KeyGenParameters(lmsParams.getKeyParams());

                engine = new FipsLMS.KeyPairGenerator(param, random);
            }
            else if (params instanceof LMSHSSKeyGenParameterSpec)
            {
                LMSKeyGenParameterSpec[] lmsParams = ((LMSHSSKeyGenParameterSpec)params).getLMSSpecs();
                FipsLMS.KeyParameters[] hssParams = new FipsLMS.KeyParameters[lmsParams.length];
                for (int i = 0; i != lmsParams.length; i++)
                {
                    hssParams[i] = lmsParams[i].getKeyParams();
                }
                param = new FipsLMS.KeyGenParameters(hssParams);

                engine = new FipsLMS.KeyPairGenerator(param, random);
            }
            else
            {
                if (params == null)
                {
                    throw new InvalidAlgorithmParameterException("parameterSpec cannot be null");
                }
                throw new InvalidAlgorithmParameterException("AlgorithmParameterSpec not recognized: " + params.getClass().getName());
            }

            initialised = true;
        }

        public KeyPair generateKeyPair()
        {
            if (!initialised)
            {
                param = new FipsLMS.KeyGenParameters(FipsLMS.lms_sha256_n32_h10.using(FipsLMS.sha256_n32_w4));

                if (random == null)
                {
                    random = provider.getDefaultSecureRandom();
                }

                engine = new FipsLMS.KeyPairGenerator(param, random);
                initialised = true;
            }

            AsymmetricKeyPair pair = engine.generateKeyPair();

            return new KeyPair(new ProvLMSPublicKey(pair.getPublicKey()), new ProvLMSPrivateKey(pair.getPrivateKey()));
        }
    }

    static class LMSSignatureSpi
        extends SignatureSpi
        implements PKCSObjectIdentifiers, X509ObjectIdentifiers
    {
        private static final byte TRAILER_IMPLICIT = (byte)0xBC;

        private final SignatureOperatorFactory operatorFactory;
        private final PublicKeyConverter publicKeyConverter;
        private final PrivateKeyConverter privateKeyConverter;
        private final BouncyCastleFipsProvider fipsProvider;
        private final AlgorithmParameterSpec originalSpec;

        protected Parameters parameters;
        protected OutputVerifier verifier;
        protected OutputSigner signer;
        protected UpdateOutputStream dataStream;

        protected AlgorithmParameters engineParams;
        protected AlgorithmParameterSpec paramSpec;

        protected AsymmetricKey key;
        protected boolean isInitState = true;

        protected LMSSignatureSpi(
            BouncyCastleFipsProvider fipsProvider,
            SignatureOperatorFactory operatorFactory,
            PublicKeyConverter publicKeyConverter,
            PrivateKeyConverter privateKeyConverter,
            Parameters parameters)
        {
            this.fipsProvider = fipsProvider;
            this.operatorFactory = operatorFactory;
            this.publicKeyConverter = publicKeyConverter;
            this.privateKeyConverter = privateKeyConverter;
            this.parameters = parameters;
            this.originalSpec = null;
        }

        protected void engineInitVerify(PublicKey publicKey)
            throws InvalidKeyException
        {
            key = publicKeyConverter.convertKey(parameters.getAlgorithm(), publicKey);
            initVerify();
            isInitState = true;
        }

        protected void engineInitSign(
            PrivateKey privateKey)
            throws InvalidKeyException
        {
            key = privateKeyConverter.convertKey(parameters.getAlgorithm(), privateKey);
            if (((AsymmetricLMSPrivateKey)key).getUsagesRemaining() == 0)
            {
                throw new InvalidKeyException("private key exhausted");
            }
            this.appRandom = fipsProvider.getDefaultSecureRandom();
            isInitState = true;
        }

        protected void engineInitSign(
            PrivateKey privateKey,
            SecureRandom random)
            throws InvalidKeyException
        {
            key = privateKeyConverter.convertKey(parameters.getAlgorithm(), privateKey);
            this.appRandom = (random != null) ? random : fipsProvider.getDefaultSecureRandom();
            isInitState = true;
        }

        protected void engineUpdate(
            byte b)
            throws SignatureException
        {
            if (isInitState && key instanceof AsymmetricLMSPrivateKey)
            {
                initSign();
            }
            isInitState = false;
            dataStream.update(b);
        }

        protected void engineUpdate(
            byte[] b,
            int off,
            int len)
            throws SignatureException
        {
            if (isInitState && key instanceof AsymmetricLMSPrivateKey)
            {
                initSign();
            }
            isInitState = false;
            dataStream.update(b, off, len);
        }

        protected byte[] engineSign()
            throws SignatureException
        {
            if (isInitState && key instanceof AsymmetricLMSPrivateKey)
            {
                initSign();
            }
            
            try
            {
                isInitState = true;
                return signer.getSignature();
            }
            catch (Exception e)
            {
                throw new SignatureException(e.toString(), e);
            }
        }

        protected boolean engineVerify(
            byte[] sigBytes)
            throws SignatureException
        {
            try
            {
                isInitState = true;
                return verifier.isVerified(sigBytes);
            }
            catch (Exception e)
            {
                throw new SignatureException(e.toString(), e);
            }
        }

        protected void engineSetParameter(
            AlgorithmParameterSpec params)
            throws InvalidAlgorithmParameterException
        {
            throw new InvalidAlgorithmParameterException("no ParameterSpec supported");
        }

        private void initVerify()
        {
            verifier = operatorFactory.createVerifier((AsymmetricPublicKey)key, parameters);
            dataStream = verifier.getVerifyingStream();
        }

        private void initSign()
            throws SignatureException
        {
            try
            {
                // TODO: should change addRandomIfNeeded in 1.1 (maybe? - it's correct in this case but is it always?
                signer = Utils.addRandomIfNeeded(operatorFactory.createSigner((AsymmetricPrivateKey)key, parameters), appRandom);
                dataStream = signer.getSigningStream();
            }
            catch (Exception e)
            {
                throw new SignatureException(e.getMessage(), e);
            }
        }

        protected AlgorithmParameters engineGetParameters()
        {
            return engineParams;
        }

        /**
         * @deprecated replaced with engineSetParameter(java.security.spec.AlgorithmParameterSpec)
         */
        protected void engineSetParameter(
            String param,
            Object value)
        {
            throw new UnsupportedOperationException("SetParameter unsupported");
        }

        /**
         * @deprecated replaced with engineGetParameters()
         */
        protected Object engineGetParameter(
            String param)
        {
            throw new UnsupportedOperationException("GetParameter unsupported");
        }
    }

    @Override
    void configure(final BouncyCastleFipsProvider provider)
    {
        provider.addAlgorithmImplementation("KeyFactory.LMS", PREFIX + "KeyFactorySpi$LMS", new GuardedEngineCreator(new EngineCreator()
        {
            public Object createInstance(Object constructorParameter)
            {
                return new KeyFactorySpi("LMS");
            }
        }));

        provider.addAlgorithmImplementation("KeyPairGenerator.LMS", PREFIX + "KeyPairGenerator", new GuardedEngineCreator(new EngineCreator()
        {
            public Object createInstance(Object constructorParameter)
            {
                return new KeyPairGeneratorSpi(provider);
            }
        }));

        provider.addAlgorithmImplementation("Signature.LMS", PREFIX + "Signature$LMS", new GuardedEngineCreator(new EngineCreator()
        {
            public Object createInstance(Object constructorParameter)
            {
                return new LMSSignatureSpi(provider, new FipsLMS.OperatorFactory(), lmsPublicKeyConverter, lmsPrivateKeyConverter, FipsLMS.SIG);
            }
        }));
        provider.addAlias("Signature", "LMS", PKCSObjectIdentifiers.id_alg_hss_lms_hashsig);
        
        registerOid(provider, PKCSObjectIdentifiers.id_alg_hss_lms_hashsig, "LMS", new KeyFactorySpi("LMS"));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy